Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
google
GitHub Repository: google/crosvm
Path: blob/main/base/src/iobuf.rs
5394 views
1
// Copyright 2023 The ChromiumOS Authors
2
// Use of this source code is governed by a BSD-style license that can be
3
// found in the LICENSE file.
4
5
//! Cross platform [`IoBuf`] and [`IoBufMut`] types wrapping `iovec`/`WSABUF`.
6
7
use std::fmt;
8
use std::fmt::Debug;
9
use std::marker::PhantomData;
10
use std::slice;
11
12
pub use crate::IoBuf;
13
14
pub(crate) trait PlatformIoBuf {
15
fn new(ptr: *mut u8, len: usize) -> Self;
16
fn len(&self) -> usize;
17
fn ptr(&self) -> *mut u8;
18
fn set_len(&mut self, len: usize);
19
fn set_ptr(&mut self, ptr: *mut u8);
20
}
21
22
/// Cross-platform mutable buffer.
23
///
24
/// This type is essentialy `std::io::IoSliceMut`, and guaranteed to be ABI-compatible with
25
/// `libc::iovec` on Linux/`WSABUF` on Windows; however, it does NOT automatically deref to `&mut
26
/// [u8]`, which is critical because it can point to guest memory. (Guest memory is implicitly
27
/// mutably borrowed by the guest, so another mutable borrow would violate Rust assumptions about
28
/// references.)
29
#[derive(Copy, Clone)]
30
#[repr(transparent)]
31
pub struct IoBufMut<'a> {
32
iobuf: IoBuf,
33
phantom: PhantomData<&'a mut [u8]>,
34
}
35
36
impl<'a> IoBufMut<'a> {
37
pub fn new(buf: &mut [u8]) -> IoBufMut<'a> {
38
// SAFETY:
39
// Safe because buf's memory is of the supplied length, and
40
// guaranteed to exist for the lifetime of the returned value.
41
unsafe { Self::from_raw_parts(buf.as_mut_ptr(), buf.len()) }
42
}
43
44
/// Creates a `IoBufMut` from a pointer and a length.
45
///
46
/// # Safety
47
///
48
/// In order to use this method safely, `addr` must be valid for reads and writes of `len` bytes
49
/// and should live for the entire duration of lifetime `'a`.
50
pub unsafe fn from_raw_parts(addr: *mut u8, len: usize) -> IoBufMut<'a> {
51
IoBufMut {
52
iobuf: IoBuf::new(addr, len),
53
phantom: PhantomData,
54
}
55
}
56
57
/// Creates a `IoBufMut` from an IoBuf.
58
///
59
/// # Safety
60
///
61
/// In order to use this method safely, `iobuf` must be valid for reads and writes through its
62
/// length and should live for the entire duration of lifetime `'a`.
63
pub unsafe fn from_iobuf(iobuf: IoBuf) -> IoBufMut<'a> {
64
IoBufMut {
65
iobuf,
66
phantom: PhantomData,
67
}
68
}
69
70
/// Advance the internal position of the buffer.
71
///
72
/// Panics if `count > self.len()`.
73
pub fn advance(&mut self, count: usize) {
74
assert!(count <= self.len());
75
76
self.iobuf.set_len(self.len() - count);
77
78
// SAFETY:
79
// Safe because we've checked that `count <= self.len()` so both the starting and resulting
80
// pointer are within the bounds of the allocation.
81
self.iobuf.set_ptr(unsafe { self.as_mut_ptr().add(count) });
82
}
83
84
/// Shorten the length of the buffer.
85
///
86
/// Has no effect if `len > self.len()`.
87
pub fn truncate(&mut self, len: usize) {
88
if len < self.len() {
89
self.iobuf.set_len(len);
90
}
91
}
92
93
#[inline]
94
pub fn len(&self) -> usize {
95
self.iobuf.len()
96
}
97
98
#[inline]
99
pub fn is_empty(&self) -> bool {
100
self.len() == 0
101
}
102
103
/// Gets a const pointer to this slice's memory.
104
#[inline]
105
pub fn as_ptr(&self) -> *const u8 {
106
self.iobuf.ptr() as *const u8
107
}
108
109
/// Gets a mutable pointer to this slice's memory.
110
#[inline]
111
pub fn as_mut_ptr(&self) -> *mut u8 {
112
self.iobuf.ptr()
113
}
114
115
/// Converts a slice of `IoBufMut`s into a slice of `IoBuf`s.
116
#[allow(clippy::wrong_self_convention)]
117
#[inline]
118
pub fn as_iobufs<'slice>(iovs: &'slice [IoBufMut<'_>]) -> &'slice [IoBuf] {
119
// SAFETY:
120
// Safe because `IoBufMut` is ABI-compatible with `IoBuf`.
121
unsafe { slice::from_raw_parts(iovs.as_ptr() as *const IoBuf, iovs.len()) }
122
}
123
124
/// Converts a mutable slice of `IoBufMut`s into a mutable slice of `IoBuf`s.
125
#[inline]
126
pub fn as_iobufs_mut<'slice>(iovs: &'slice mut [IoBufMut<'_>]) -> &'slice mut [IoBuf] {
127
// SAFETY:
128
// Safe because `IoBufMut` is ABI-compatible with `IoBuf`.
129
unsafe { slice::from_raw_parts_mut(iovs.as_mut_ptr() as *mut IoBuf, iovs.len()) }
130
}
131
}
132
133
impl AsRef<IoBuf> for IoBufMut<'_> {
134
fn as_ref(&self) -> &IoBuf {
135
&self.iobuf
136
}
137
}
138
139
impl AsMut<IoBuf> for IoBufMut<'_> {
140
fn as_mut(&mut self) -> &mut IoBuf {
141
&mut self.iobuf
142
}
143
}
144
145
// SAFETY:
146
// It's safe to implement Send + Sync for this type for the same reason that `std::io::IoSliceMut`
147
// is Send + Sync. Internally, it contains a pointer and a length. The integer length is safely Send
148
// + Sync. There's nothing wrong with sending a pointer between threads and de-referencing the
149
// pointer requires an unsafe block anyway. See also https://github.com/rust-lang/rust/pull/70342.
150
unsafe impl Send for IoBufMut<'_> {}
151
// SAFETY: See comments for impl Send
152
unsafe impl Sync for IoBufMut<'_> {}
153
154
impl Debug for IoBufMut<'_> {
155
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
156
f.debug_struct("IoBufMut")
157
.field("ptr", &self.iobuf.ptr())
158
.field("len", &self.iobuf.len())
159
.finish()
160
}
161
}
162
163