Skip to main content

ntex_bytes/buf/
uninit_slice.rs

1use std::ops::{
2    Index, IndexMut, Range, RangeFrom, RangeFull, RangeInclusive, RangeTo, RangeToInclusive,
3};
4use std::{fmt, mem::MaybeUninit, ptr};
5
6/// Uninitialized byte slice.
7///
8/// Returned by `BufMut::chunk_mut()`, the referenced byte slice may be
9/// uninitialized. The wrapper provides safe access without introducing
10/// undefined behavior.
11///
12/// The safety invariants of this wrapper are:
13///
14///  1. Reading from an `UninitSlice` is undefined behavior.
15///  2. Writing uninitialized bytes to an `UninitSlice` is undefined behavior.
16///
17/// The difference between `&mut UninitSlice` and `&mut [MaybeUninit<u8>]` is
18/// that it is possible in safe code to write uninitialized bytes to an
19/// `&mut [MaybeUninit<u8>]`, which this type prohibits.
20#[repr(transparent)]
21pub struct UninitSlice([MaybeUninit<u8>]);
22
23impl UninitSlice {
24    /// Create a `&mut UninitSlice` from a pointer and a length.
25    ///
26    /// # Safety
27    ///
28    /// The caller must ensure that `ptr` references a valid memory region owned
29    /// by the caller representing a byte slice for the duration of `'a`.
30    ///
31    /// # Examples
32    ///
33    /// ```
34    /// use ntex_bytes::buf::UninitSlice;
35    ///
36    /// let bytes = b"hello world".to_vec();
37    /// let ptr = bytes.as_ptr() as *mut _;
38    /// let len = bytes.len();
39    ///
40    /// let slice = unsafe { UninitSlice::from_raw_parts_mut(ptr, len) };
41    /// ```
42    #[inline]
43    pub unsafe fn from_raw_parts_mut<'a>(ptr: *mut u8, len: usize) -> &'a mut UninitSlice {
44        UninitSlice::from_uninit_mut(core::slice::from_raw_parts_mut(ptr.cast(), len))
45    }
46
47    #[inline]
48    fn from_uninit(slice: &[MaybeUninit<u8>]) -> &UninitSlice {
49        // SAFETY: `UninitSlice` is a transparent wrapper of `[MaybeUninit<u8>]`, with the same
50        // lifetime.
51        unsafe { &*(ptr::from_ref(slice) as *const UninitSlice) }
52    }
53
54    #[inline]
55    fn from_uninit_mut(slice: &mut [MaybeUninit<u8>]) -> &mut UninitSlice {
56        // SAFETY: `UninitSlice` is a transparent wrapper of `[MaybeUninit<u8>]`, preserving
57        // exclusive access.
58        unsafe { &mut *(ptr::from_mut(slice) as *mut UninitSlice) }
59    }
60
61    /// Write a single byte at the specified offset.
62    ///
63    /// # Panics
64    ///
65    /// The function panics if `index` is out of bounds.
66    ///
67    /// # Examples
68    ///
69    /// ```
70    /// use ntex_bytes::buf::UninitSlice;
71    ///
72    /// let mut data = [b'f', b'o', b'o'];
73    /// let slice = unsafe { UninitSlice::from_raw_parts_mut(data.as_mut_ptr(), 3) };
74    ///
75    /// slice.write_byte(0, b'b');
76    ///
77    /// assert_eq!(b"boo", &data[..]);
78    /// ```
79    #[inline]
80    pub fn write_byte(&mut self, index: usize, byte: u8) {
81        assert!(index < self.len());
82
83        // SAFETY: `index < len` was checked above, so the pointer addresses a writable byte.
84        unsafe { self[index..].as_mut_ptr().write(byte) }
85    }
86
87    /// Copies bytes  from `src` into `self`.
88    ///
89    /// The length of `src` must be the same as `self`.
90    ///
91    /// # Panics
92    ///
93    /// The function panics if `src` has a different length than `self`.
94    ///
95    /// # Examples
96    ///
97    /// ```
98    /// use ntex_bytes::buf::UninitSlice;
99    ///
100    /// let mut data = [b'f', b'o', b'o'];
101    /// let slice = unsafe { UninitSlice::from_raw_parts_mut(data.as_mut_ptr(), 3) };
102    ///
103    /// slice.copy_from_slice(b"bar");
104    ///
105    /// assert_eq!(b"bar", &data[..]);
106    /// ```
107    #[inline]
108    pub fn copy_from_slice(&mut self, src: &[u8]) {
109        use core::ptr;
110
111        assert_eq!(self.len(), src.len());
112
113        // SAFETY: The lengths match, and the exclusive destination slice cannot overlap `src`.
114        unsafe {
115            ptr::copy_nonoverlapping(src.as_ptr(), self.as_mut_ptr(), self.len());
116        }
117    }
118
119    /// Return a raw pointer to the slice's buffer.
120    ///
121    /// # Pointer usage
122    ///
123    /// The caller **must not** read from the referenced memory and **must not**
124    /// write **uninitialized** bytes to the slice either.
125    ///
126    /// # Examples
127    ///
128    /// ```
129    /// use ntex_bytes::BufMut;
130    ///
131    /// let mut data = [0, 1, 2];
132    /// let mut slice = &mut data[..];
133    /// let ptr = BufMut::chunk_mut(&mut slice).as_mut_ptr();
134    /// ```
135    #[inline]
136    pub fn as_mut_ptr(&mut self) -> *mut u8 {
137        self.0.as_mut_ptr().cast()
138    }
139
140    /// Returns the number of bytes in the slice.
141    ///
142    /// # Examples
143    ///
144    /// ```
145    /// use ntex_bytes::BufMut;
146    ///
147    /// let mut data = [0, 1, 2];
148    /// let mut slice = &mut data[..];
149    /// let len = BufMut::chunk_mut(&mut slice).len();
150    ///
151    /// assert_eq!(len, 3);
152    /// ```
153    #[inline]
154    #[allow(clippy::len_without_is_empty)]
155    pub fn len(&self) -> usize {
156        self.0.len()
157    }
158
159    /// Returns the slice as a mutable slice of [`MaybeUninit<u8>`].
160    ///
161    /// # Safety
162    ///
163    /// The memory may already be initialized, for example when the slice was
164    /// returned by the [`BufMut`](crate::BufMut) implementation for
165    /// `&mut [u8]`. The caller **must not** write uninitialized bytes to the
166    /// returned slice.
167    ///
168    /// # Examples
169    ///
170    /// ```
171    /// use ntex_bytes::BufMut;
172    ///
173    /// let mut data = [0, 1, 2];
174    /// let mut slice = &mut data[..];
175    /// let uninit = unsafe { BufMut::chunk_mut(&mut slice).as_uninit_slice_mut() };
176    /// uninit[0].write(b'a');
177    ///
178    /// assert_eq!(data[0], b'a');
179    /// ```
180    #[inline]
181    pub unsafe fn as_uninit_slice_mut(&mut self) -> &mut [MaybeUninit<u8>] {
182        &mut self.0
183    }
184}
185
186impl fmt::Debug for UninitSlice {
187    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
188        fmt.debug_struct("UninitSlice[...]").finish()
189    }
190}
191
192macro_rules! impl_index {
193    ($($t:ty),*) => {
194        $(
195            impl Index<$t> for UninitSlice {
196                type Output = UninitSlice;
197
198                #[inline]
199                fn index(&self, index: $t) -> &UninitSlice {
200                    UninitSlice::from_uninit(&self.0[index])
201                }
202            }
203
204            impl IndexMut<$t> for UninitSlice {
205                #[inline]
206                fn index_mut(&mut self, index: $t) -> &mut UninitSlice {
207                    UninitSlice::from_uninit_mut(&mut self.0[index])
208                }
209            }
210        )*
211    };
212}
213
214impl_index!(
215    Range<usize>,
216    RangeFrom<usize>,
217    RangeFull,
218    RangeInclusive<usize>,
219    RangeTo<usize>,
220    RangeToInclusive<usize>
221);
222
223#[cfg(test)]
224mod tests {
225    use super::*;
226
227    /// STATEMENT: `UninitSlice` supports standard range indexing and writes through uninitialized-slice views.
228    ///
229    /// HOW:
230    /// - Wrap an eight-byte array, check six range lengths, and write `a` and `b` through `as_uninit_slice_mut`.
231    /// - Verify the underlying array begins with `ab`.
232    #[test]
233    fn index_and_uninit_access() {
234        let mut data = [0u8; 8];
235        // SAFETY: The pointer and length cover the live array, exclusively borrowed until the last
236        // slice use.
237        let slice = unsafe { UninitSlice::from_raw_parts_mut(data.as_mut_ptr(), data.len()) };
238
239        assert_eq!(slice[..].len(), 8);
240        assert_eq!(slice[2..].len(), 6);
241        assert_eq!(slice[..3].len(), 3);
242        assert_eq!(slice[..=3].len(), 4);
243        assert_eq!(slice[1..3].len(), 2);
244        assert_eq!(slice[1..=3].len(), 3);
245
246        // SAFETY: Only initialized bytes are written, preserving initialization of the underlying
247        // array.
248        unsafe {
249            slice.as_uninit_slice_mut()[0].write(b'a');
250            slice.as_uninit_slice_mut()[1].write(b'b');
251        }
252        assert_eq!(&data[..2], b"ab");
253    }
254}