Skip to main content

compio_buf/
slice.rs

1use std::{
2    mem::MaybeUninit,
3    ops::{Deref, DerefMut},
4};
5
6use crate::*;
7
8/// An owned view into a contiguous sequence of bytes.
9///
10/// This is similar to Rust slices (`&buf[..]`) but owns the underlying buffer.
11/// This type is useful for performing io-uring read and write operations using
12/// a subset of a buffer.
13///
14/// Slices are created using [`IoBufExt::slice`].
15///
16/// # Examples
17///
18/// Creating a slice
19///
20/// ```
21/// use compio_buf::IoBufExt;
22///
23/// let buf = b"hello world";
24/// let slice = buf.slice(..5);
25///
26/// assert_eq!(&slice[..], b"hello");
27/// ```
28#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
29pub struct Slice<T> {
30    buffer: T,
31    begin: usize,
32    end: Option<usize>,
33}
34
35impl<T> Slice<T> {
36    /// # Safety
37    ///
38    /// User must ensure that `begin` is less than or equal to the length of the
39    /// underlying buffer.
40    pub(crate) unsafe fn new(buffer: T, begin: usize, end: Option<usize>) -> Self {
41        Self { buffer, begin, end }
42    }
43
44    /// Offset in the underlying buffer at which this slice starts.
45    pub fn begin(&self) -> usize {
46        self.begin
47    }
48
49    /// Sets the begin offset of the slice.
50    ///
51    /// # Safety
52    ///
53    /// User must ensure that `begin` is less than or equal to the length of the
54    /// underlying buffer.
55    pub unsafe fn set_begin_unchecked(&mut self, begin: usize) {
56        self.begin = begin;
57    }
58
59    /// Offset in the underlying buffer at which this slice ends.
60    pub fn end(&self) -> Option<usize> {
61        self.end
62    }
63
64    /// Sets the end offset of the slice.
65    pub fn set_end(&mut self, end: usize) {
66        self.end = Some(end);
67    }
68
69    /// Gets a reference to the underlying buffer.
70    ///
71    /// This method escapes the slice's view.
72    pub fn as_inner(&self) -> &T {
73        &self.buffer
74    }
75
76    /// Gets a mutable reference to the underlying buffer.
77    ///
78    /// This method escapes the slice's view.
79    pub fn as_inner_mut(&mut self) -> &mut T {
80        &mut self.buffer
81    }
82}
83
84impl<T: IoBuf> Slice<T> {
85    /// Sets the begin offset of the slice.
86    ///
87    /// # Panics
88    ///
89    /// Panics if `begin` is greater than the length of the underlying buffer.
90    pub fn set_begin(&mut self, begin: usize) {
91        assert!(begin <= self.buffer.buf_len());
92        // Safety: we just checked the invariant
93        unsafe { self.set_begin_unchecked(begin) }
94    }
95}
96
97impl<T: IoBuf> Slice<Slice<T>> {
98    /// Flatten nested slices into a single slice.
99    pub fn flatten(self) -> Slice<T> {
100        let large_begin = self.buffer.begin;
101        let large_end = self.buffer.end;
102
103        let new_begin = large_begin + self.begin;
104        let new_end = match (self.end, large_end) {
105            (Some(small_end), Some(large_end)) => Some((large_begin + small_end).min(large_end)),
106            (Some(small_end), None) => Some(large_begin + small_end),
107            (None, large_end) => large_end,
108        };
109
110        // Safety: inner.begin + outer.begin <= buf_len
111        unsafe { Slice::new(self.buffer.buffer, new_begin, new_end) }
112    }
113}
114
115#[cfg(feature = "bytes")]
116impl Slice<bytes::Bytes> {
117    /// A convenient function to slice the underlying [`Bytes`] with
118    /// [`Bytes::slice`].
119    ///
120    /// The returned `Bytes` will deref to the same byte slice as this
121    /// [`Slice`].
122    ///
123    /// [`Bytes`]: bytes::Bytes
124    /// [`Bytes::slice`]: bytes::Bytes::slice
125    pub fn slice_bytes(&self) -> bytes::Bytes {
126        let range = self.initialized_range();
127        bytes::Bytes::slice(&self.buffer, range)
128    }
129}
130
131impl<T: IoBuf> Slice<T> {
132    /// Offset in the underlying buffer at which this slice ends. If it does not
133    /// exist or exceeds the buffer length, returns the buffer length.
134    fn end_or_len(&self) -> usize {
135        let len = self.buffer.buf_len();
136        self.end.unwrap_or(len).min(len)
137    }
138
139    /// Range of initialized bytes in the slice.
140    fn initialized_range(&self) -> std::ops::Range<usize> {
141        let end = self.end_or_len();
142        self.begin..end
143    }
144}
145
146impl<T: IoBufMut> Slice<T> {
147    /// Offset in the underlying buffer at which this slice ends. If it does not
148    /// exist or exceeds the buffer capacity, returns the buffer capacity.
149    fn end_or_cap(&mut self) -> usize {
150        let cap = self.buffer.buf_capacity();
151        self.end.unwrap_or(cap).min(cap)
152    }
153
154    /// Full range of the slice, include uninitialized bytes.
155    fn range(&mut self) -> std::ops::Range<usize> {
156        let end = self.end_or_cap();
157        self.begin..end
158    }
159}
160
161impl<T: IoBuf> Deref for Slice<T> {
162    type Target = [u8];
163
164    fn deref(&self) -> &Self::Target {
165        let range = self.initialized_range();
166        let bytes = self.buffer.as_init();
167        &bytes[range]
168    }
169}
170
171impl<T: IoBufMut> DerefMut for Slice<T> {
172    fn deref_mut(&mut self) -> &mut Self::Target {
173        let range = self.initialized_range();
174        let bytes = self.buffer.as_mut_slice();
175        &mut bytes[range]
176    }
177}
178
179impl<T: IoBuf> IoBuf for Slice<T> {
180    fn as_init(&self) -> &[u8] {
181        self.deref()
182    }
183}
184
185impl<T: IoBufMut> IoBufMut for Slice<T> {
186    unsafe fn as_uninit(&mut self) -> &mut [MaybeUninit<u8>] {
187        let range = self.range();
188        // SAFETY: Every byte in the initialized part of this range is also part
189        // of the underlying buffer's initialized bytes.
190        let bytes = unsafe { self.buffer.as_uninit() };
191        &mut bytes[range]
192    }
193
194    fn reserve(&mut self, len: usize) -> Result<(), ReserveError> {
195        if self.end.is_some() {
196            // Cannot reserve on a fixed-size slice
197            Err(ReserveError::NotSupported)
198        } else {
199            self.buffer.reserve(len)
200        }
201    }
202
203    fn reserve_exact(&mut self, len: usize) -> Result<(), ReserveExactError> {
204        if self.end.is_some() {
205            // Cannot reserve on a fixed-size slice
206            Err(ReserveExactError::NotSupported)
207        } else {
208            self.buffer.reserve_exact(len)
209        }
210    }
211}
212
213impl<T: SetLen> SetLen for Slice<T> {
214    unsafe fn set_len(&mut self, len: usize) {
215        unsafe { self.buffer.set_len(self.begin + len) }
216    }
217}
218
219impl<T> IntoInner for Slice<T> {
220    type Inner = T;
221
222    fn into_inner(self) -> Self::Inner {
223        self.buffer
224    }
225}
226
227/// Return type for [`IoVectoredBuf::slice`] and
228/// [`IoVectoredBufMut::slice_mut`].
229///
230/// # Behavior
231///
232/// When constructing the [`VectoredSlice`], it will first compute how
233/// many buffers to skip. Imaging vectored buffers as concatenated slices, there
234/// will be uninitialized "slots" in between. This slice type provides two
235/// behaviors of how to skip through those slots, controlled by the marker type
236/// `B`:
237///
238/// - [`IoVectoredBuf::slice`]: Ignore uninitialized slots, i.e., skip
239///   `begin`-many **initialized** bytes.
240/// - [`IoVectoredBufMut::slice_mut`]: Consider uninitialized slots, i.e., skip
241///   `begin`-many bytes.
242///
243/// This will only affect how the slice is being constructed. The resulting
244/// slice will always expose all of the remaining bytes, no matter initialized
245/// or not (in particular, [`IoVectoredBufMut::iter_uninit_slice`]).
246pub struct VectoredSlice<T> {
247    buf: T,
248    begin: usize,
249    idx: usize,
250    offset: usize,
251}
252
253impl<T> IntoInner for VectoredSlice<T> {
254    type Inner = T;
255
256    fn into_inner(self) -> Self::Inner {
257        self.buf
258    }
259}
260
261impl<T> VectoredSlice<T> {
262    /// Offset in the underlying buffer at which this slice starts.
263    pub fn begin(&self) -> usize {
264        self.begin
265    }
266
267    /// Gets a reference to the underlying buffer.
268    ///
269    /// This method escapes the slice's view.
270    pub fn as_inner(&self) -> &T {
271        &self.buf
272    }
273
274    /// Gets a mutable reference to the underlying buffer.
275    ///
276    /// This method escapes the slice's view.
277    pub fn as_inner_mut(&mut self) -> &mut T {
278        &mut self.buf
279    }
280
281    pub(crate) fn new(buf: T, begin: usize, idx: usize, offset: usize) -> Self {
282        Self {
283            buf,
284            begin,
285            idx,
286            offset,
287        }
288    }
289}
290
291impl<T: IoVectoredBuf> IoVectoredBuf for VectoredSlice<T> {
292    fn iter_slice(&self) -> impl Iterator<Item = &[u8]> {
293        let mut offset = self.offset;
294        self.buf.iter_slice().skip(self.idx).map(move |buf| {
295            let ret = &buf[offset..];
296            offset = 0;
297            ret
298        })
299    }
300}
301
302impl<T: SetLen> SetLen for VectoredSlice<T> {
303    unsafe fn set_len(&mut self, len: usize) {
304        unsafe { self.buf.set_len(self.begin + len) }
305    }
306}
307
308impl<T: IoVectoredBufMut> IoVectoredBufMut for VectoredSlice<T> {
309    unsafe fn iter_uninit_slice(&mut self) -> impl Iterator<Item = &mut [MaybeUninit<u8>]> {
310        let mut offset = self.offset;
311        // SAFETY: No initialized byte of the underlying buffers can be
312        // de-initialized through this iterator.
313        unsafe { self.buf.iter_uninit_slice() }
314            .skip(self.idx)
315            .map(move |buf| {
316                let ret = &mut buf[offset..];
317                offset = 0;
318                ret
319            })
320    }
321}
322
323#[test]
324fn test_slice() {
325    let buf = b"hello world";
326    let slice = buf.slice(6..);
327    assert_eq!(slice.as_init(), b"world");
328
329    let slice = buf.slice(..5);
330    assert_eq!(slice.as_init(), b"hello");
331
332    let slice = buf.slice(3..8);
333    assert_eq!(slice.as_init(), b"lo wo");
334
335    let slice = buf.slice(..);
336    assert_eq!(slice.as_init(), b"hello world");
337
338    let slice = buf.slice(11..);
339    assert_eq!(slice.as_init(), b"");
340}