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 [`IoBuf::slice`].
15///
16/// # Examples
17///
18/// Creating a slice
19///
20/// ```
21/// use compio_buf::IoBuf;
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    fn as_uninit(&mut self) -> &mut [MaybeUninit<u8>] {
187        let range = self.range();
188        let bytes = self.buffer.as_uninit();
189        &mut bytes[range]
190    }
191
192    fn reserve(&mut self, len: usize) -> Result<(), ReserveError> {
193        if self.end.is_some() {
194            // Cannot reserve on a fixed-size slice
195            Err(ReserveError::NotSupported)
196        } else {
197            self.buffer.reserve(len)
198        }
199    }
200
201    fn reserve_exact(&mut self, len: usize) -> Result<(), ReserveExactError> {
202        if self.end.is_some() {
203            // Cannot reserve on a fixed-size slice
204            Err(ReserveExactError::NotSupported)
205        } else {
206            self.buffer.reserve_exact(len)
207        }
208    }
209}
210
211impl<T: SetLen> SetLen for Slice<T> {
212    unsafe fn set_len(&mut self, len: usize) {
213        unsafe { self.buffer.set_len(self.begin + len) }
214    }
215}
216
217impl<T> IntoInner for Slice<T> {
218    type Inner = T;
219
220    fn into_inner(self) -> Self::Inner {
221        self.buffer
222    }
223}
224
225/// Return type for [`IoVectoredBuf::slice`] and
226/// [`IoVectoredBufMut::slice_mut`].
227///
228/// # Behavior
229///
230/// When constructing the [`VectoredSlice`], it will first compute how
231/// many buffers to skip. Imaging vectored buffers as concatenated slices, there
232/// will be uninitialized "slots" in between. This slice type provides two
233/// behaviors of how to skip through those slots, controlled by the marker type
234/// `B`:
235///
236/// - [`IoVectoredBuf::slice`]: Ignore uninitialized slots, i.e., skip
237///   `begin`-many **initialized** bytes.
238/// - [`IoVectoredBufMut::slice_mut`]: Consider uninitialized slots, i.e., skip
239///   `begin`-many bytes.
240///
241/// This will only affect how the slice is being constructed. The resulting
242/// slice will always expose all of the remaining bytes, no matter initialized
243/// or not (in particular, [`IoVectoredBufMut::iter_uninit_slice`]).
244pub struct VectoredSlice<T> {
245    buf: T,
246    begin: usize,
247    idx: usize,
248    offset: usize,
249}
250
251impl<T> IntoInner for VectoredSlice<T> {
252    type Inner = T;
253
254    fn into_inner(self) -> Self::Inner {
255        self.buf
256    }
257}
258
259impl<T> VectoredSlice<T> {
260    /// Offset in the underlying buffer at which this slice starts.
261    pub fn begin(&self) -> usize {
262        self.begin
263    }
264
265    /// Gets a reference to the underlying buffer.
266    ///
267    /// This method escapes the slice's view.
268    pub fn as_inner(&self) -> &T {
269        &self.buf
270    }
271
272    /// Gets a mutable reference to the underlying buffer.
273    ///
274    /// This method escapes the slice's view.
275    pub fn as_inner_mut(&mut self) -> &mut T {
276        &mut self.buf
277    }
278
279    pub(crate) fn new(buf: T, begin: usize, idx: usize, offset: usize) -> Self {
280        Self {
281            buf,
282            begin,
283            idx,
284            offset,
285        }
286    }
287}
288
289impl<T: IoVectoredBuf> IoVectoredBuf for VectoredSlice<T> {
290    fn iter_slice(&self) -> impl Iterator<Item = &[u8]> {
291        let mut offset = self.offset;
292        self.buf.iter_slice().skip(self.idx).map(move |buf| {
293            let ret = &buf[offset..];
294            offset = 0;
295            ret
296        })
297    }
298}
299
300impl<T: SetLen> SetLen for VectoredSlice<T> {
301    unsafe fn set_len(&mut self, len: usize) {
302        unsafe { self.buf.set_len(self.begin + len) }
303    }
304}
305
306impl<T: IoVectoredBufMut> IoVectoredBufMut for VectoredSlice<T> {
307    fn iter_uninit_slice(&mut self) -> impl Iterator<Item = &mut [MaybeUninit<u8>]> {
308        let mut offset = self.offset;
309        self.buf.iter_uninit_slice().skip(self.idx).map(move |buf| {
310            let ret = &mut buf[offset..];
311            offset = 0;
312            ret
313        })
314    }
315}
316
317#[test]
318fn test_slice() {
319    let buf = b"hello world";
320    let slice = buf.slice(6..);
321    assert_eq!(slice.as_init(), b"world");
322
323    let slice = buf.slice(..5);
324    assert_eq!(slice.as_init(), b"hello");
325
326    let slice = buf.slice(3..8);
327    assert_eq!(slice.as_init(), b"lo wo");
328
329    let slice = buf.slice(..);
330    assert_eq!(slice.as_init(), b"hello world");
331
332    let slice = buf.slice(11..);
333    assert_eq!(slice.as_init(), b"");
334}