base/
iobuf.rs

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
7use std::fmt;
8use std::fmt::Debug;
9use std::marker::PhantomData;
10use std::slice;
11
12pub use crate::IoBuf;
13
14pub(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)]
31pub struct IoBufMut<'a> {
32    iobuf: IoBuf,
33    phantom: PhantomData<&'a mut [u8]>,
34}
35
36impl<'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
133impl AsRef<IoBuf> for IoBufMut<'_> {
134    fn as_ref(&self) -> &IoBuf {
135        &self.iobuf
136    }
137}
138
139impl 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.
150unsafe impl Send for IoBufMut<'_> {}
151// SAFETY: See comments for impl Send
152unsafe impl Sync for IoBufMut<'_> {}
153
154impl 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}