Skip to main content

tempest_io/
buf.rs

1use bytes::{Bytes, BytesMut};
2
3/// # Safety
4///
5/// Implementors must ensure [`stable_ptr`](IoBuf::stable_ptr) returns a pointer
6/// that remains valid and pinned for the entire duration of any I/O operation
7/// the buffer is passed to.
8pub unsafe trait IoBuf {
9    /// Returns a stable pointer to the start of the initialized data.
10    fn stable_ptr(&self) -> *const u8;
11
12    /// Number of initialized bytes, valid to read.
13    fn bytes_init(&self) -> usize;
14
15    /// Total capacity, including uninitialized memory.
16    /// This is what gets passed to the kernel for reads.
17    fn bytes_total(&self) -> usize;
18
19    /// Returns a bounded view into this buffer.
20    fn slice(self, range: impl std::ops::RangeBounds<usize>) -> Slice<Self>
21    where
22        Self: Sized,
23    {
24        let begin = match range.start_bound() {
25            std::ops::Bound::Included(&n) => n,
26            std::ops::Bound::Unbounded => 0,
27            _ => unreachable!(),
28        };
29        let end = match range.end_bound() {
30            std::ops::Bound::Excluded(&n) => n,
31            std::ops::Bound::Included(&n) => n + 1,
32            std::ops::Bound::Unbounded => self.bytes_total(),
33        };
34        assert!(begin <= end && end <= self.bytes_total());
35        Slice::new(self, begin, end)
36    }
37}
38
39/// # Safety
40///
41/// Implementors must ensure [`stable_mut_ptr`](IoBufMut::stable_mut_ptr) returns
42/// a pointer that remains valid and pinned for the entire duration of any I/O
43/// operation the buffer is passed to.
44pub unsafe trait IoBufMut: IoBuf {
45    /// Returns a stable mutable pointer to the start of the buffer.
46    fn stable_mut_ptr(&mut self) -> *mut u8;
47
48    /// Mark the first `pos` bytes as initialized.
49    ///
50    /// # Safety
51    ///
52    /// Caller must ensure all bytes from `stable_mut_ptr()` up to `pos`
53    /// are actually initialized and may be read.
54    unsafe fn set_init(&mut self, pos: usize);
55
56    /// Clear this buffer, setting the initialized bytes to 0.
57    fn clear(&mut self) {
58        // SAFETY: it is always safe, since we dont assume anything is initialized
59        unsafe { self.set_init(0) };
60    }
61}
62
63/// A bounded view into an owned [`IoBuf`] or [`IoBufMut`] buffer.
64///
65/// Allows passing a subset of a buffer to an I/O operation without
66/// splitting or consuming it. The original buffer is reclaimed via
67/// [`into_inner`](Slice::into_inner) after the operation completes.
68// TODO: add example section once VirtualIo is implemented
69#[derive(Debug)]
70pub struct Slice<B> {
71    buf: B,
72    begin: usize,
73    end: usize,
74}
75
76impl<B: IoBuf> Slice<B> {
77    /// Creates a new slice into `buf` bounded by `[begin, end)`.
78    ///
79    /// # Panics
80    ///
81    /// Panics if `begin > end` or `end > buf.bytes_total()`.
82    pub fn new(buf: B, begin: usize, end: usize) -> Self {
83        assert!(begin <= end && end <= buf.bytes_total());
84        Self { buf, begin, end }
85    }
86
87    /// Consumes the slice and returns the underlying buffer.
88    pub fn into_inner(self) -> B {
89        self.buf
90    }
91
92    /// Returns the length of initialized bytes of this slice.
93    pub fn len(&self) -> usize {
94        self.bytes_init()
95    }
96
97    /// Returns `true` if the length of this slice is zero.
98    pub fn is_empty(&self) -> bool {
99        self.bytes_init() == 0
100    }
101}
102
103unsafe impl<B: IoBuf> IoBuf for Slice<B> {
104    fn stable_ptr(&self) -> *const u8 {
105        unsafe { self.buf.stable_ptr().add(self.begin) }
106    }
107
108    fn bytes_init(&self) -> usize {
109        // slice may reach into uninitialized bytes
110        self.buf
111            .bytes_init()
112            .saturating_sub(self.begin)
113            .min(self.end - self.begin)
114    }
115
116    fn bytes_total(&self) -> usize {
117        self.end - self.begin
118    }
119}
120
121unsafe impl<B: IoBufMut> IoBufMut for Slice<B> {
122    fn stable_mut_ptr(&mut self) -> *mut u8 {
123        unsafe { self.buf.stable_mut_ptr().add(self.begin) }
124    }
125
126    unsafe fn set_init(&mut self, pos: usize) {
127        // pos is relative to the slice start, adjust to the full buffer
128        unsafe { self.buf.set_init(self.begin + pos) };
129    }
130}
131
132impl<B: IoBuf> AsRef<[u8]> for Slice<B> {
133    fn as_ref(&self) -> &[u8] {
134        let ptr = self.stable_ptr();
135        let len = self.bytes_init();
136        // SAFETY: ptr is valid and initialized up until ptr + len
137        unsafe { std::slice::from_raw_parts(ptr, len) }
138    }
139}
140
141pub enum MaybeRegistered<R, F> {
142    Registered(R),
143    Fallback(F),
144}
145
146unsafe impl<R: IoBuf, F: IoBuf> IoBuf for MaybeRegistered<R, F> {
147    fn stable_ptr(&self) -> *const u8 {
148        match self {
149            Self::Registered(r) => r.stable_ptr(),
150            Self::Fallback(f) => f.stable_ptr(),
151        }
152    }
153
154    fn bytes_init(&self) -> usize {
155        match self {
156            Self::Registered(r) => r.bytes_init(),
157            Self::Fallback(f) => f.bytes_init(),
158        }
159    }
160
161    fn bytes_total(&self) -> usize {
162        match self {
163            Self::Registered(r) => r.bytes_total(),
164            Self::Fallback(f) => f.bytes_total(),
165        }
166    }
167}
168
169unsafe impl<R: IoBufMut, F: IoBufMut> IoBufMut for MaybeRegistered<R, F> {
170    fn stable_mut_ptr(&mut self) -> *mut u8 {
171        match self {
172            Self::Registered(r) => r.stable_mut_ptr(),
173            Self::Fallback(f) => f.stable_mut_ptr(),
174        }
175    }
176
177    unsafe fn set_init(&mut self, pos: usize) {
178        // SAFETY: R and F are required to implement set_init correctly
179        unsafe {
180            match self {
181                Self::Registered(r) => r.set_init(pos),
182                Self::Fallback(f) => f.set_init(pos),
183            }
184        }
185    }
186}
187
188unsafe impl<const N: usize> IoBuf for [u8; N] {
189    fn stable_ptr(&self) -> *const u8 {
190        self.as_ptr()
191    }
192
193    fn bytes_init(&self) -> usize {
194        N
195    }
196
197    fn bytes_total(&self) -> usize {
198        N
199    }
200}
201
202unsafe impl<const N: usize> IoBufMut for [u8; N] {
203    fn stable_mut_ptr(&mut self) -> *mut u8 {
204        self.as_mut_ptr()
205    }
206
207    unsafe fn set_init(&mut self, _pos: usize) {} // always fully initialized
208}
209
210unsafe impl IoBuf for &'static [u8] {
211    fn stable_ptr(&self) -> *const u8 {
212        self.as_ptr()
213    }
214
215    fn bytes_init(&self) -> usize {
216        self.len()
217    }
218
219    fn bytes_total(&self) -> usize {
220        self.len()
221    }
222}
223
224unsafe impl IoBuf for Bytes {
225    fn stable_ptr(&self) -> *const u8 {
226        self.as_ptr()
227    }
228
229    fn bytes_init(&self) -> usize {
230        self.len()
231    }
232
233    fn bytes_total(&self) -> usize {
234        // `Bytes` does not have a capacity, since it is immutable
235        self.len()
236    }
237}
238
239unsafe impl IoBuf for BytesMut {
240    fn stable_ptr(&self) -> *const u8 {
241        self.as_ptr()
242    }
243
244    fn bytes_init(&self) -> usize {
245        self.len()
246    }
247
248    fn bytes_total(&self) -> usize {
249        self.capacity()
250    }
251}
252
253unsafe impl IoBufMut for BytesMut {
254    fn stable_mut_ptr(&mut self) -> *mut u8 {
255        self.as_mut_ptr()
256    }
257
258    unsafe fn set_init(&mut self, pos: usize) {
259        // SAFETY: caller must ensure all bytes up to `pos` are valid
260        unsafe { self.set_len(pos) };
261    }
262}
263
264unsafe impl IoBuf for Vec<u8> {
265    fn stable_ptr(&self) -> *const u8 {
266        self.as_ptr()
267    }
268    fn bytes_init(&self) -> usize {
269        self.len()
270    }
271    fn bytes_total(&self) -> usize {
272        self.capacity()
273    }
274}
275
276unsafe impl IoBufMut for Vec<u8> {
277    fn stable_mut_ptr(&mut self) -> *mut u8 {
278        self.as_mut_ptr()
279    }
280
281    unsafe fn set_init(&mut self, pos: usize) {
282        // SAFETY: caller ensures bytes up to pos are initialized
283        unsafe { self.set_len(pos) };
284    }
285}