bytes/buf/
uninit_slice.rs

1use core::fmt;
2use core::mem::MaybeUninit;
3use core::ops::{
4    Index, IndexMut, Range, RangeFrom, RangeFull, RangeInclusive, RangeTo, RangeToInclusive,
5};
6
7/// Uninitialized byte slice.
8///
9/// Returned by `BufMut::chunk_mut()`, the referenced byte slice may be
10/// uninitialized. The wrapper provides safe access without introducing
11/// undefined behavior.
12///
13/// The safety invariants of this wrapper are:
14///
15///  1. Reading from an `UninitSlice` is undefined behavior.
16///  2. Writing uninitialized bytes to an `UninitSlice` is undefined behavior.
17///
18/// The difference between `&mut UninitSlice` and `&mut [MaybeUninit<u8>]` is
19/// that it is possible in safe code to write uninitialized bytes to an
20/// `&mut [MaybeUninit<u8>]`, which this type prohibits.
21#[repr(transparent)]
22pub struct UninitSlice([MaybeUninit<u8>]);
23
24impl UninitSlice {
25    /// Create a `&mut UninitSlice` from a pointer and a length.
26    ///
27    /// # Safety
28    ///
29    /// The caller must ensure that `ptr` references a valid memory region owned
30    /// by the caller representing a byte slice for the duration of `'a`.
31    ///
32    /// # Examples
33    ///
34    /// ```
35    /// use bytes::buf::UninitSlice;
36    ///
37    /// let bytes = b"hello world".to_vec();
38    /// let ptr = bytes.as_ptr() as *mut _;
39    /// let len = bytes.len();
40    ///
41    /// let slice = unsafe { UninitSlice::from_raw_parts_mut(ptr, len) };
42    /// ```
43    #[inline]
44    pub unsafe fn from_raw_parts_mut<'a>(ptr: *mut u8, len: usize) -> &'a mut UninitSlice {
45        let maybe_init: &mut [MaybeUninit<u8>] =
46            core::slice::from_raw_parts_mut(ptr as *mut _, len);
47        &mut *(maybe_init as *mut [MaybeUninit<u8>] as *mut UninitSlice)
48    }
49
50    /// Write a single byte at the specified offset.
51    ///
52    /// # Panics
53    ///
54    /// The function panics if `index` is out of bounds.
55    ///
56    /// # Examples
57    ///
58    /// ```
59    /// use bytes::buf::UninitSlice;
60    ///
61    /// let mut data = [b'f', b'o', b'o'];
62    /// let slice = unsafe { UninitSlice::from_raw_parts_mut(data.as_mut_ptr(), 3) };
63    ///
64    /// slice.write_byte(0, b'b');
65    ///
66    /// assert_eq!(b"boo", &data[..]);
67    /// ```
68    #[inline]
69    pub fn write_byte(&mut self, index: usize, byte: u8) {
70        assert!(index < self.len());
71
72        unsafe { self[index..].as_mut_ptr().write(byte) }
73    }
74
75    /// Copies bytes  from `src` into `self`.
76    ///
77    /// The length of `src` must be the same as `self`.
78    ///
79    /// # Panics
80    ///
81    /// The function panics if `src` has a different length than `self`.
82    ///
83    /// # Examples
84    ///
85    /// ```
86    /// use bytes::buf::UninitSlice;
87    ///
88    /// let mut data = [b'f', b'o', b'o'];
89    /// let slice = unsafe { UninitSlice::from_raw_parts_mut(data.as_mut_ptr(), 3) };
90    ///
91    /// slice.copy_from_slice(b"bar");
92    ///
93    /// assert_eq!(b"bar", &data[..]);
94    /// ```
95    #[inline]
96    pub fn copy_from_slice(&mut self, src: &[u8]) {
97        use core::ptr;
98
99        assert_eq!(self.len(), src.len());
100
101        unsafe {
102            ptr::copy_nonoverlapping(src.as_ptr(), self.as_mut_ptr(), self.len());
103        }
104    }
105
106    /// Return a raw pointer to the slice's buffer.
107    ///
108    /// # Safety
109    ///
110    /// The caller **must not** read from the referenced memory and **must not**
111    /// write **uninitialized** bytes to the slice either.
112    ///
113    /// # Examples
114    ///
115    /// ```
116    /// use bytes::BufMut;
117    ///
118    /// let mut data = [0, 1, 2];
119    /// let mut slice = &mut data[..];
120    /// let ptr = BufMut::chunk_mut(&mut slice).as_mut_ptr();
121    /// ```
122    #[inline]
123    pub fn as_mut_ptr(&mut self) -> *mut u8 {
124        self.0.as_mut_ptr() as *mut _
125    }
126
127    /// Return a `&mut [MaybeUninit<u8>]` to this slice's buffer.
128    ///
129    /// # Safety
130    ///
131    /// The caller **must not** read from the referenced memory and **must not** write
132    /// **uninitialized** bytes to the slice either. This is because `BufMut` implementation
133    /// that created the `UninitSlice` knows which parts are initialized. Writing uninitalized
134    /// bytes to the slice may cause the `BufMut` to read those bytes and trigger undefined
135    /// behavior.
136    ///
137    /// # Examples
138    ///
139    /// ```
140    /// use bytes::BufMut;
141    ///
142    /// let mut data = [0, 1, 2];
143    /// let mut slice = &mut data[..];
144    /// unsafe {
145    ///     let uninit_slice = BufMut::chunk_mut(&mut slice).as_uninit_slice_mut();
146    /// };
147    /// ```
148    #[inline]
149    pub unsafe fn as_uninit_slice_mut<'a>(&'a mut self) -> &'a mut [MaybeUninit<u8>] {
150        &mut *(self as *mut _ as *mut [MaybeUninit<u8>])
151    }
152
153    /// Returns the number of bytes in the slice.
154    ///
155    /// # Examples
156    ///
157    /// ```
158    /// use bytes::BufMut;
159    ///
160    /// let mut data = [0, 1, 2];
161    /// let mut slice = &mut data[..];
162    /// let len = BufMut::chunk_mut(&mut slice).len();
163    ///
164    /// assert_eq!(len, 3);
165    /// ```
166    #[inline]
167    pub fn len(&self) -> usize {
168        self.0.len()
169    }
170}
171
172impl fmt::Debug for UninitSlice {
173    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
174        fmt.debug_struct("UninitSlice[...]").finish()
175    }
176}
177
178macro_rules! impl_index {
179    ($($t:ty),*) => {
180        $(
181            impl Index<$t> for UninitSlice {
182                type Output = UninitSlice;
183
184                #[inline]
185                fn index(&self, index: $t) -> &UninitSlice {
186                    let maybe_uninit: &[MaybeUninit<u8>] = &self.0[index];
187                    unsafe { &*(maybe_uninit as *const [MaybeUninit<u8>] as *const UninitSlice) }
188                }
189            }
190
191            impl IndexMut<$t> for UninitSlice {
192                #[inline]
193                fn index_mut(&mut self, index: $t) -> &mut UninitSlice {
194                    let maybe_uninit: &mut [MaybeUninit<u8>] = &mut self.0[index];
195                    unsafe { &mut *(maybe_uninit as *mut [MaybeUninit<u8>] as *mut UninitSlice) }
196                }
197            }
198        )*
199    };
200}
201
202impl_index!(
203    Range<usize>,
204    RangeFrom<usize>,
205    RangeFull,
206    RangeInclusive<usize>,
207    RangeTo<usize>,
208    RangeToInclusive<usize>
209);