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}