musli_utils/
fixed.rs

1//! Containers which can store up to a fixed number of uninitialized bytes on
2//! the stack and read into and from it.
3
4use core::fmt;
5use core::mem::{self, MaybeUninit};
6use core::ops::{Deref, DerefMut};
7use core::ptr;
8use core::slice;
9
10use musli::{Buf, Context};
11
12use crate::writer::Writer;
13
14/// A fixed-size bytes storage which keeps track of how much has been initialized.
15pub struct FixedBytes<const N: usize> {
16    /// Data storage.
17    data: [MaybeUninit<u8>; N],
18    /// How many bytes have been initialized.
19    init: usize,
20}
21
22impl<const N: usize> FixedBytes<N> {
23    /// Construct a new fixed bytes array storage.
24    #[inline]
25    pub const fn new() -> Self {
26        Self {
27            // SAFETY: MaybeUnint::uninit_array is not stable.
28            data: unsafe { MaybeUninit::<[MaybeUninit<u8>; N]>::uninit().assume_init() },
29            init: 0,
30        }
31    }
32
33    /// Construct a fixed bytes while asserting that the given runtime capacity isn't violated.
34    pub fn with_capacity(capacity: usize) -> Self {
35        assert!(
36            capacity < N,
37            "Requested capacity {capacity} is larger than {N}"
38        );
39        Self::new()
40    }
41
42    /// Get the length of the collection.
43    #[inline]
44    pub const fn len(&self) -> usize {
45        self.init
46    }
47
48    /// Test if the current container is empty.
49    #[inline]
50    pub const fn is_empty(&self) -> bool {
51        self.init == 0
52    }
53
54    /// Clear the [FixedBytes] container.
55    #[inline]
56    pub fn clear(&mut self) {
57        self.init = 0;
58    }
59
60    /// Get the remaining capacity of the [FixedBytes].
61    #[inline]
62    pub const fn remaining(&self) -> usize {
63        N.saturating_sub(self.init)
64    }
65
66    /// Coerce into the underlying bytes if all of them have been initialized.
67    #[inline]
68    pub fn into_bytes(self) -> Option<[u8; N]> {
69        if self.init == N {
70            // SAFETY: All of the bytes in the sequence have been initialized
71            // and can be safety transmuted.
72            //
73            // Method of transmuting comes from the implementation of
74            // `MaybeUninit::array_assume_init` which is not yet stable.
75            unsafe { Some((&self.data as *const _ as *const [u8; N]).read()) }
76        } else {
77            None
78        }
79    }
80
81    /// Coerce into the slice of initialized memory which is present.
82    #[inline]
83    pub fn as_slice(&self) -> &[u8] {
84        if self.init == 0 {
85            return &[];
86        }
87
88        // SAFETY: We've asserted that `initialized` accounts for the number of
89        // bytes that have been initialized.
90        unsafe { core::slice::from_raw_parts(self.data.as_ptr().cast(), self.init) }
91    }
92
93    /// Coerce into the mutable slice of initialized memory which is present.
94    #[inline]
95    pub fn as_mut_slice(&mut self) -> &mut [u8] {
96        if self.init == 0 {
97            return &mut [];
98        }
99
100        // SAFETY: We've asserted that `initialized` accounts for the number of
101        // bytes that have been initialized.
102        unsafe { core::slice::from_raw_parts_mut(self.data.as_mut_ptr().cast(), self.init) }
103    }
104
105    /// Try and push a single byte.
106    #[inline]
107    pub fn push(&mut self, value: u8) -> bool {
108        if N.saturating_sub(self.init) == 0 {
109            return false;
110        }
111
112        unsafe {
113            self.data
114                .as_mut_ptr()
115                .cast::<u8>()
116                .add(self.init)
117                .write(value)
118        }
119
120        self.init += 1;
121        true
122    }
123
124    /// Try and extend from the given slice.
125    #[inline]
126    pub fn extend_from_slice(&mut self, source: &[u8]) -> bool {
127        if source.len() > N.saturating_sub(self.init) {
128            return false;
129        }
130
131        unsafe {
132            let dst = (self.data.as_mut_ptr() as *mut u8).add(self.init);
133            ptr::copy_nonoverlapping(source.as_ptr(), dst, source.len());
134        }
135
136        self.init = self.init.wrapping_add(source.len());
137        true
138    }
139
140    /// Try and extend from the given slice.
141    #[inline]
142    pub fn write_bytes<C>(&mut self, cx: &C, source: &[u8]) -> Result<(), C::Error>
143    where
144        C: ?Sized + Context,
145    {
146        if !self.extend_from_slice(source) {
147            return Err(cx.message(FixedBytesOverflow {
148                at: self.init,
149                additional: source.len(),
150                capacity: N,
151            }));
152        }
153
154        Ok(())
155    }
156}
157
158impl<const N: usize> Deref for FixedBytes<N> {
159    type Target = [u8];
160
161    #[inline]
162    fn deref(&self) -> &Self::Target {
163        self.as_slice()
164    }
165}
166
167impl<const N: usize> DerefMut for FixedBytes<N> {
168    #[inline]
169    fn deref_mut(&mut self) -> &mut Self::Target {
170        self.as_mut_slice()
171    }
172}
173
174impl<const N: usize> Default for FixedBytes<N> {
175    #[inline]
176    fn default() -> Self {
177        Self::new()
178    }
179}
180
181impl<const N: usize> Writer for FixedBytes<N> {
182    type Mut<'this> = &'this mut Self where Self: 'this;
183
184    #[inline]
185    fn borrow_mut(&mut self) -> Self::Mut<'_> {
186        self
187    }
188
189    #[inline]
190    fn write_buffer<C, B>(&mut self, cx: &C, buffer: B) -> Result<(), C::Error>
191    where
192        C: ?Sized + Context,
193        B: Buf,
194    {
195        // SAFETY: the buffer never outlives this function call.
196        self.write_bytes(cx, buffer.as_slice())
197    }
198
199    #[inline]
200    fn write_bytes<C>(&mut self, cx: &C, bytes: &[u8]) -> Result<(), C::Error>
201    where
202        C: ?Sized + Context,
203    {
204        FixedBytes::write_bytes(self, cx, bytes)?;
205        cx.advance(bytes.len());
206        Ok(())
207    }
208}
209
210/// Capacity error raised by trying to write to a [FixedBytes] with no remaining
211/// capacity.
212#[derive(Debug)]
213#[allow(missing_docs)]
214#[non_exhaustive]
215pub(crate) struct FixedBytesOverflow {
216    at: usize,
217    additional: usize,
218    capacity: usize,
219}
220
221impl fmt::Display for FixedBytesOverflow {
222    #[inline]
223    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
224        let FixedBytesOverflow {
225            at,
226            additional,
227            capacity,
228        } = self;
229
230        write!(
231            f,
232            "Tried to write {additional} bytes at {at} with capacity {capacity}"
233        )
234    }
235}
236
237/// An error raised when we are at capacity.
238#[non_exhaustive]
239pub(crate) struct CapacityError;
240
241/// A fixed capacity vector allocated on the stack.
242pub(crate) struct FixedVec<T, const N: usize> {
243    data: [MaybeUninit<T>; N],
244    len: usize,
245}
246
247impl<T, const N: usize> FixedVec<T, N> {
248    /// Construct a new empty fixed vector.
249    pub(crate) const fn new() -> FixedVec<T, N> {
250        unsafe {
251            FixedVec {
252                data: MaybeUninit::uninit().assume_init(),
253                len: 0,
254            }
255        }
256    }
257
258    #[inline]
259    pub(crate) fn as_ptr(&self) -> *const T {
260        self.data.as_ptr() as *const T
261    }
262
263    #[inline]
264    pub(crate) fn as_mut_ptr(&mut self) -> *mut T {
265        self.data.as_mut_ptr() as *mut T
266    }
267
268    #[inline]
269    pub(crate) fn as_slice(&self) -> &[T] {
270        unsafe { slice::from_raw_parts(self.as_ptr(), self.len) }
271    }
272
273    #[inline]
274    pub(crate) fn as_mut_slice(&mut self) -> &mut [T] {
275        unsafe { slice::from_raw_parts_mut(self.as_mut_ptr(), self.len) }
276    }
277
278    /// Try to push an element onto the fixed vector.
279    pub(crate) fn try_push(&mut self, element: T) -> Result<(), CapacityError> {
280        if self.len >= N {
281            return Err(CapacityError);
282        }
283
284        unsafe {
285            ptr::write(self.as_mut_ptr().wrapping_add(self.len), element);
286            self.len += 1;
287        }
288
289        Ok(())
290    }
291
292    /// Pop the last element in the fixed vector.
293    pub(crate) fn pop(&mut self) -> Option<T> {
294        if self.len == 0 {
295            return None;
296        }
297
298        unsafe {
299            let new_len = self.len - 1;
300            self.len = new_len;
301            Some(ptr::read(self.as_ptr().wrapping_add(new_len)))
302        }
303    }
304
305    pub(crate) fn clear(&mut self) {
306        if self.len == 0 {
307            return;
308        }
309
310        let len = mem::take(&mut self.len);
311
312        if mem::needs_drop::<T>() {
313            unsafe {
314                let tail = slice::from_raw_parts_mut(self.as_mut_ptr(), len);
315                ptr::drop_in_place(tail);
316            }
317        }
318    }
319}
320
321impl<T, const N: usize> Deref for FixedVec<T, N> {
322    type Target = [T];
323
324    #[inline]
325    fn deref(&self) -> &Self::Target {
326        self.as_slice()
327    }
328}
329
330impl<T, const N: usize> DerefMut for FixedVec<T, N> {
331    #[inline]
332    fn deref_mut(&mut self) -> &mut Self::Target {
333        self.as_mut_slice()
334    }
335}
336
337impl<T, const N: usize> Drop for FixedVec<T, N> {
338    #[inline]
339    fn drop(&mut self) {
340        self.clear()
341    }
342}