Skip to main content

cocoon_tpm_utils_common/
fixed_vec.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright 2025 SUSE LLC
3// Author: Nicolai Stange <nstange@suse.de>
4
5//! [`FixedVec`] -- non-resizeable heap allocations with efficient memory
6//! footprint.
7
8#![deny(unsafe_op_in_unsafe_fn)]
9
10extern crate alloc;
11
12#[cfg(feature = "zeroize")]
13use zeroize;
14
15use core::{cmp, convert, fmt, iter, marker, mem, ops, ptr, slice};
16
17#[cfg(doc)]
18use alloc::vec::Vec;
19
20/// Error type returned for [`FixedVec`] allocation failures.
21#[derive(Clone, Copy, Debug)]
22pub struct FixedVecMemoryAllocationFailure;
23
24/// Error type returned by [`FixedVec::new_from_fn()`].
25#[derive(Clone, Copy, Debug)]
26pub enum FixedVecNewFromFnError<E: Sized> {
27    /// Memory allocation failure.
28    MemoryAllocationFailure,
29    /// The provided initialization function returned the wrapped error.
30    FnError(E),
31}
32
33impl<E: Sized> From<FixedVecMemoryAllocationFailure> for FixedVecNewFromFnError<E> {
34    fn from(_value: FixedVecMemoryAllocationFailure) -> Self {
35        Self::MemoryAllocationFailure
36    }
37}
38
39impl From<FixedVecNewFromFnError<convert::Infallible>> for FixedVecMemoryAllocationFailure {
40    fn from(value: FixedVecNewFromFnError<convert::Infallible>) -> Self {
41        match value {
42            FixedVecNewFromFnError::MemoryAllocationFailure => FixedVecMemoryAllocationFailure,
43            FixedVecNewFromFnError::FnError(e) => match e {
44                // Infallible.
45            },
46        }
47    }
48}
49
50/// Number of least significant "tag" bits in a [`FixedVec`] heap allocation
51/// pointer value reserved for encoding the length, if possible.
52const PTR_TAG_BITS: u32 = 3;
53/// Mask for the least significant [`PTR_TAG_BITS`] bits.
54const PTR_TAG_MASK: usize = (1usize << PTR_TAG_BITS) - 1;
55
56/// Manage heap allocations for the case that the [`FixedVec`]'s length is not
57/// stored within the allocated memory.
58///
59/// The heap allocation's internal format differs slightly between the cases
60/// that the [`FixedVec`]'s length is encoded in its pointer's tag bits or
61/// within the allocated memory respectively.
62///
63/// `FixedVecDataWithoutLen` implements functionality related to handling the
64/// former. The heap allocation simply comprises the [`FixedVec`]'s sequence of
65/// `T` elements.
66///
67/// # See also:
68///
69/// * [`FixedVecDataWithLen`].
70struct FixedVecDataWithoutLen<T: Sized> {
71    _phantom: marker::PhantomData<fn() -> *const T>,
72}
73
74impl<T: Sized> FixedVecDataWithoutLen<T> {
75    /// Allocate memory suitable for storing a sequence of `T` elements of
76    /// specified length.
77    ///
78    /// On success, a pointer to the allocation is returned. Use
79    /// [`data_ptr()`](Self::data_ptr) to obtain a pointer to the sequence
80    /// of `T` elements.
81    ///
82    /// # Arguments:
83    ///
84    /// * `len` - Number of `T` elements to be stored in the [`FixedVec`].
85    ///
86    /// # Safety:
87    ///
88    /// * `T` must not be a ZST and `len` must not be zero.
89    /// * On success, it's guaranteed that `len * size_of::<T>()` will not
90    ///   exceed [`isize::MAX`].
91    unsafe fn try_allocate(len: usize) -> Result<ptr::NonNull<u8>, FixedVecMemoryAllocationFailure> {
92        debug_assert!(mem::size_of::<T>() != 0);
93        debug_assert!(len != 0);
94        let size = len
95            .checked_mul(mem::size_of::<T>())
96            .ok_or(FixedVecMemoryAllocationFailure)?;
97        let align = (1usize << PTR_TAG_BITS).max(mem::align_of::<T>());
98        // Note: this fails if the aligned size exceeds isize::MAX.
99        let layout = alloc::alloc::Layout::from_size_align(size, align).map_err(|_| FixedVecMemoryAllocationFailure)?;
100        // SAFETY: T is not a ZST and len is not zero, hence the layout has non-zero
101        // size.
102        let allocation_ptr = unsafe { alloc::alloc::alloc(layout) };
103        if allocation_ptr.is_null() {
104            return Err(FixedVecMemoryAllocationFailure);
105        }
106        // SAFETY: it's been checked above that the pointer is non-null.
107        Ok(unsafe { ptr::NonNull::new_unchecked(allocation_ptr) })
108    }
109
110    /// Deallocate the memory.
111    ///
112    /// # Arguments:
113    ///
114    /// * `allocation_ptr` - Pointer to the memory previously obtained from
115    ///   [`try_allocate()`](Self::try_allocate).
116    ///
117    /// # Safety:
118    ///
119    /// `allocation_ptr` must have been allocated by [`Self::try_allocate()`]
120    /// with matching `len` and not been deallocated already.
121    unsafe fn deallocate(allocation_ptr: ptr::NonNull<u8>, len: usize) {
122        // No overflow checks here, they've already been passed
123        // in Self::try_allocate().
124        let size = len * mem::size_of::<T>();
125        let align = (1usize << PTR_TAG_BITS).max(mem::align_of::<T>());
126        // SAFETY: this reconstructs the very same Layout already instantiated from
127        // Self::try_allocate().
128        let layout = unsafe { alloc::alloc::Layout::from_size_align_unchecked(size, align) };
129        // SAFETY: The reconstructed layout matches that used by Self::try_allocate()
130        // when allocating the memory referenced by allocation_ptr.
131        unsafe { alloc::alloc::dealloc(allocation_ptr.as_ptr(), layout) };
132    }
133
134    /// Obtain a pointer to the sequence of `T` elements within the heap
135    /// allocation.
136    ///
137    /// # Arguments:
138    ///
139    /// * `allocation_ptr` - Pointer to the memory previously obtained from
140    ///   [`try_allocate()`](Self::try_allocate).
141    ///
142    /// # Safety:
143    ///
144    /// * `allocation_ptr` must have been allocated by [`Self::try_allocate()`]
145    ///   and not been [deallocated](Self::deallocate) yet.
146    /// * The returned pointer points to the beginning of contiguously
147    ///   allocated, properly aligned sequence of memory slots suitable for
148    ///   storing a `T` each, of number as requested for the `len` argument
149    ///   initially passed to [`Self::try_allocate()`]. The backing memory's
150    ///   total size does not exceed `isize::MAX`, as per the prior
151    ///   [`Self::try_allocate()`] having been successful.
152    unsafe fn data_ptr(allocation_ptr: ptr::NonNull<u8>) -> ptr::NonNull<T> {
153        let data_ptr = allocation_ptr.as_ptr() as *mut T;
154        // SAFETY: the pointer had been NonNull on input, and still is.
155        unsafe { ptr::NonNull::new_unchecked(data_ptr) }
156    }
157}
158
159/// Manage heap allocations for the case that the [`FixedVec`]'s length is
160/// stored within the allocated memory.
161///
162/// The heap allocation's internal format differs slightly between the cases
163/// that the [`FixedVec`]'s length is encoded in its pointer's tag bits or
164/// within the allocated memory respectively.
165///
166/// `FixedVecDataWithLen` implements functionality related to handling the
167/// latter. The [`FixedVec`]'s length is stored first, followed by its (aligned)
168/// sequence of `T` elements.
169///
170/// # See also:
171///
172/// * [`FixedVecDataWithoutLen`].
173struct FixedVecDataWithLen<T: Sized> {
174    _phantom: marker::PhantomData<fn() -> *const T>,
175}
176
177impl<T: Sized> FixedVecDataWithLen<T> {
178    /// Allocate memory suitable for storing a sequence of `T` elements of
179    /// specified length.
180    ///
181    /// On success, a pointer to the allocation is returned. Use
182    /// [`data_ptr()`](Self::data_ptr) to obtain a pointer to the sequence
183    /// of `T` elements.
184    ///
185    /// # Arguments:
186    ///
187    /// * `len` - Number of `T` elements to be stored in the [`FixedVec`].
188    ///
189    /// # Safety:
190    ///
191    /// * `T` must not be a ZST and `len` must not be zero.
192    /// * On success, it's guaranteed that `len * size_of::<T>()` will not
193    ///   exceed [`isize::MAX`].
194    unsafe fn try_allocate(len: usize) -> Result<ptr::NonNull<u8>, FixedVecMemoryAllocationFailure> {
195        debug_assert!(mem::size_of::<T>() != 0);
196        debug_assert!(len != 0);
197        let size = len
198            .checked_mul(mem::size_of::<T>())
199            .and_then(|size| size.checked_add(Self::data_offset()))
200            .ok_or(FixedVecMemoryAllocationFailure)?;
201        let align = (1usize << PTR_TAG_BITS)
202            .max(mem::align_of::<usize>())
203            .max(mem::align_of::<T>());
204        // Note: this fails if the aligned size exceeds isize::MAX.
205        let layout = alloc::alloc::Layout::from_size_align(size, align).map_err(|_| FixedVecMemoryAllocationFailure)?;
206        // SAFETY: T is not a ZST and len is not zero, hence the layout has non-zero
207        // size.
208        let allocation_ptr = unsafe { alloc::alloc::alloc(layout) };
209        if allocation_ptr.is_null() {
210            return Err(FixedVecMemoryAllocationFailure);
211        }
212        // SAFETY: the memory has been layout such that there's a properly aligned usize
213        // at the head.
214        unsafe { (allocation_ptr as *mut usize).write(len) };
215        // SAFETY: it's been checked above that the pointer is non-null.
216        Ok(unsafe { ptr::NonNull::new_unchecked(allocation_ptr) })
217    }
218
219    /// Deallocate the memory.
220    ///
221    /// # Arguments:
222    ///
223    /// * `allocation_ptr` - Pointer to the memory previously obtained from
224    ///   [`try_allocate()`](Self::try_allocate).
225    ///
226    /// # Safety:
227    ///
228    /// `allocation_ptr` must have been allocated by [`Self::try_allocate()`]
229    /// with matching `len` and not been deallocated already.
230    unsafe fn deallocate(allocation_ptr: ptr::NonNull<u8>, len: usize) {
231        // No overflow checks here, they've already been passed
232        // in Self::try_allocate().
233        let size = len * mem::size_of::<T>() + Self::data_offset();
234        let align = (1usize << PTR_TAG_BITS)
235            .max(mem::align_of::<usize>())
236            .max(mem::align_of::<T>());
237        // SAFETY: this reconstructs the very same Layout already instantiated from
238        // Self::try_allocate().
239        let layout = unsafe { alloc::alloc::Layout::from_size_align_unchecked(size, align) };
240        // SAFETY: The reconstructed layout matches that used by Self::try_allocate()
241        // when allocating the memory referenced by allocation_ptr.
242        unsafe { alloc::alloc::dealloc(allocation_ptr.as_ptr(), layout) };
243    }
244
245    /// Retrieve the [`FixedVec`] length stored within the heap allocation.
246    ///
247    /// # Arguments:
248    ///
249    /// * `allocation_ptr` - Pointer to the memory previously obtained from
250    ///   [`try_allocate()`](Self::try_allocate).
251    ///
252    /// # Safety:
253    ///
254    /// `allocation_ptr` must have been allocated by [`Self::try_allocate()`]
255    /// and not been [deallocated](Self::deallocate) yet.
256    unsafe fn data_len(allocation_ptr: ptr::NonNull<u8>) -> usize {
257        let ptr_to_len = allocation_ptr.as_ptr() as *const usize;
258        // SAFETY: The allocation_ptr obtained from Self::try_allocate() points at an
259        // usize at the head and has been initialized with the length value
260        // there.
261        unsafe { *ptr_to_len }
262    }
263
264    /// Offset of the sequence of `T` elements within the heap allocation.
265    const fn data_offset() -> usize {
266        assert!(mem::align_of::<T>().is_power_of_two());
267        mem::size_of::<usize>() + (mem::size_of::<usize>().wrapping_neg() & (mem::align_of::<T>() - 1))
268    }
269
270    /// Obtain a pointer to the sequence of `T` elements within the heap
271    /// allocation.
272    ///
273    /// # Arguments:
274    ///
275    /// * `allocation_ptr` - Pointer to the memory previously obtained from
276    ///   [`try_allocate()`](Self::try_allocate).
277    ///
278    /// # Safety:
279    ///
280    /// * `allocation_ptr` must have been allocated by [`Self::try_allocate()`]
281    ///   and not been [deallocated](Self::deallocate) yet.
282    /// * The returned pointer points to the beginning of a contiguously
283    ///   allocated, properly aligned sequence of memory slots suitable for
284    ///   storing a `T` each, of number as requested for the `len` argument
285    ///   initially passed to [`Self::try_allocate()`]. The backing memory's
286    ///   total size does not exceed `isize::MAX`, as per the prior
287    ///   [`Self::try_allocate()`] having been successful.
288    unsafe fn data_ptr(allocation_ptr: ptr::NonNull<u8>) -> ptr::NonNull<T> {
289        // SAFETY: stays in the bounds of the allocation, as per the layout construction
290        // in Self::try_allocate().
291        let data_ptr = (unsafe { allocation_ptr.as_ptr().add(Self::data_offset()) }) as *mut T;
292        // SAFETY: the pointer had been NonNull on input, and still is.
293        unsafe { ptr::NonNull::new_unchecked(data_ptr) }
294    }
295}
296
297/// Representation of [`FixedVec::tagged_ptr`].
298union FixedVecTaggedPtr {
299    /// Tagged pointer to the data for non-ZST element types.
300    ///
301    /// If a [null pointer](ptr::null_mut), then the [`FixedVec`] is empty and
302    /// no memory is allocated. Otherwise, `non_zst_tagged_ptr` is a tagged
303    /// pointer, storing the tag in the least significant [`PTR_TAG_BITS`]:
304    /// * If the least significant [`PTR_TAG_BITS`] are equal to
305    ///   [`PTR_TAG_MASK`], i.e. the maximum possible encodable value, then the
306    ///   pointer points to a memory in the [`FixedVecDataWithLen`] format, i.e.
307    ///   the [`FixedVec`]'s length is stored in front of the data in the memory
308    ///   allocation.
309    /// * Otherwise the [`FixedVec`]'s length is a power of two, and the tag
310    ///   encodes the base-2 logarithm thereof, relative to the [`FixedVec`]'s
311    ///   `BASE_LEN_LOG2` generic parameter.
312    non_zst_tagged_ptr: *mut u8,
313    /// The [`FixedVec`] length for ZST element types.
314    ///
315    /// For ZST element types, no memory is ever allocated and
316    /// the tagged pointer always stores the [`FixedVec`] length.
317    zst_data_len: usize,
318}
319
320/// Non-resizeable heap allocations with efficient memory footprint.
321///
322/// In order to support resizing operations, a standard Rust [`struct Vec`](Vec)
323/// is relatively large: it comprises a pointer to the heap allocation itself,
324/// alongsize two [`usize`]s for the [`Vec`]'s [length](Vec::len) and
325/// [capacity](Vec::capacity) each. In situations where there are many instances
326/// thereof, and resizing is generally not needed, such that as for IO buffers,
327/// this can incur quite some unnecessary overhead.
328///
329/// `FixedVec` provides a more memory efficient alternative. Resizing operations
330/// are not supported, and therefore there is no notion of a capacity.
331/// The `FixedVec` length `usize` is stored externally within the heap
332/// allocation, except for some special values of particular relevance to the
333/// intended use-cases:
334/// * Either if the length is zero,
335/// * or if it is a power of two, with a base-2 logarithm greater or equal to
336///   the `BASE_LEN_LOG2` generic parameter, and less than some fixed bound
337///   internal to the implementation, then it will get encoded into (the least
338///   significant bits of) the heap pointer value.
339///
340/// In either case, the memory occupied by a `struct FixedVec` is always that of
341/// a (thin) pointer, and by dimensioning the `BASE_LEN_LOG2` parameter properly
342/// in accordance with the expected usecase, even the `FixedVec`'s length usize
343/// often doesn't need to get accomodated for within the heap allocation.
344pub struct FixedVec<T: Sized, const BASE_LEN_LOG2: u32> {
345    /// The tagged pointer.
346    ///
347    /// If T is a ZST, then [`FixedVecTaggedPtr::zst_data_len`] is active.
348    /// Otherwise [`FixedVecTaggedPtr::non_zst_tagged_ptr`], i.e. a tagged
349    /// pointer to the heap allocation, if any, is active.
350    tagged_ptr: FixedVecTaggedPtr,
351    _phantom: marker::PhantomData<fn() -> *const T>,
352}
353
354impl<T: Sized, const BASE_LEN_LOG2: u32> FixedVec<T, BASE_LEN_LOG2> {
355    /// Instantitate a new empty [`FixedVec`].
356    pub const fn new_empty() -> Self {
357        if mem::size_of::<T>() == 0 {
358            Self {
359                tagged_ptr: FixedVecTaggedPtr {
360                    // For ZST T, the tagged_ptr's zst_data_len union field is active.
361                    zst_data_len: 0,
362                },
363                _phantom: marker::PhantomData,
364            }
365        } else {
366            Self {
367                tagged_ptr: FixedVecTaggedPtr {
368                    // For non-ZST T, the tagged_ptr's non_zst_tagged_ptr union field is active.
369                    non_zst_tagged_ptr: ptr::null_mut(),
370                },
371                _phantom: marker::PhantomData,
372            }
373        }
374    }
375
376    /// Instantiate a [`FixedVec`] of specified length and initialize its
377    /// elements with values produced by a provided function.
378    ///
379    /// Instantiate a [`FixedVec`] of length `len`, and initialize its elements
380    /// with the values produced by invoking `f` with the respective element
381    /// index. `f` may return an error, in which case its propagated back by
382    /// means of an [`FixedVecNewFromFnError::FnError`]. Otherwise, on
383    /// success of `f`, the associated [`FixedVec`] element is initialized
384    /// with the returned value.
385    ///
386    /// # Arguments:
387    ///
388    /// * `len` - The number of elements the instantiated [`FixedVec`] shall
389    ///   contain.
390    /// * `f` - The provided element initialization function.
391    pub fn new_from_fn<E: Sized, F: FnMut(usize) -> Result<T, E>>(
392        len: usize,
393        mut f: F,
394    ) -> Result<Self, FixedVecNewFromFnError<E>> {
395        let (v, data_ptr) = if mem::size_of::<T>() == 0 {
396            let v = Self {
397                tagged_ptr: FixedVecTaggedPtr {
398                    // For ZST T, the tagged_ptr's zst_data_len union field is active.
399                    zst_data_len: len,
400                },
401                _phantom: marker::PhantomData,
402            };
403            if len == 0 {
404                return Ok(v);
405            }
406            // Don't invoke Self::drop() until all elements have been initialized.
407            (mem::ManuallyDrop::new(v), ptr::NonNull::dangling())
408        } else if len == 0 {
409            let v = Self {
410                tagged_ptr: FixedVecTaggedPtr {
411                    // For non-ZST T, the tagged_ptr's non_zst_tagged_ptr union field is active.
412                    non_zst_tagged_ptr: ptr::null_mut(),
413                },
414                _phantom: marker::PhantomData,
415            };
416            return Ok(v);
417        } else if BASE_LEN_LOG2 < usize::BITS
418            && len.is_power_of_two()
419            && len >> BASE_LEN_LOG2 != 0
420            && len >> BASE_LEN_LOG2 < (1usize << PTR_TAG_MASK)
421        {
422            // The len value qualifies for encoding in the tagged_ptr's tag.
423            let ptr_tag = (len.ilog2() - BASE_LEN_LOG2) as usize;
424            // SAFETY: T is not a ZST and len iz not zero.
425            let untagged_ptr = unsafe { FixedVecDataWithoutLen::<T>::try_allocate(len)? };
426            // SAFETY: untagged_ptr has just been obtained from
427            // FixedVecDataWithoutLen::try_allocate().
428            let data_ptr = unsafe { FixedVecDataWithoutLen::<T>::data_ptr(untagged_ptr) };
429            let v = Self {
430                tagged_ptr: FixedVecTaggedPtr {
431                    // For non-ZST T, the tagged_ptr's non_zst_tagged_ptr union field is active.
432                    non_zst_tagged_ptr: untagged_ptr.as_ptr().map_addr(|untagged_ptr| untagged_ptr | ptr_tag),
433                },
434                _phantom: marker::PhantomData,
435            };
436            // Don't invoke Self::drop() until all elements have been initialized.
437            (mem::ManuallyDrop::new(v), data_ptr)
438        } else {
439            // The len value does not qualify for encoding in the tagged_ptr's tag. It must
440            // get stored at the allocated memory's head.
441            let ptr_tag = PTR_TAG_MASK;
442            // SAFETY: T is not a ZST and len iz not zero.
443            let untagged_ptr = unsafe { FixedVecDataWithLen::<T>::try_allocate(len)? };
444            // SAFETY: untagged_ptr has just been obtained from
445            // FixedVecDataWithLen::try_allocate().
446            let data_ptr = unsafe { FixedVecDataWithLen::data_ptr(untagged_ptr) };
447            let v = Self {
448                // For non-ZST T, the tagged_ptr's non_zst_tagged_ptr union field is active.
449                tagged_ptr: FixedVecTaggedPtr {
450                    non_zst_tagged_ptr: untagged_ptr.as_ptr().map_addr(|untagged_ptr| untagged_ptr | ptr_tag),
451                },
452                _phantom: marker::PhantomData,
453            };
454            // Don't invoke Self::drop() until all elements have been initialized.
455            (mem::ManuallyDrop::new(v), data_ptr)
456        };
457
458        let mut element_ptr = data_ptr;
459        for i in 0..len {
460            let value = match f(i) {
461                Ok(value) => value,
462                Err(e) => {
463                    // Drop the elements initialized so far.
464                    let mut element_ptr = data_ptr;
465                    for _ in 0..i {
466                        // SAFETY:
467                        // - If T is a ZST, then data_ptr and hence element_ptr is ptr::dangling_mut(),
468                        //   hence properly aligned and non-null.
469                        // - Otherwise data_ptr has been obtained from either
470                        //   FixedVecDataWithoutLen::data_ptr() or FixedVecDataWithLen::data_ptr() on an
471                        //   allocation obtained from a prior successful
472                        //   FixedVecDataWithoutLen::try_allocate() or
473                        //   FixedVecDataWithLen::try_allocate() invoked with len respectively. Thus,
474                        //   considering the loop bounds, element_ptr is valid for reads and writes, is
475                        //   aligned and points at an initialized T.
476                        unsafe { element_ptr.drop_in_place() };
477                        // SAFETY: Either T is a ZST, or element_ptr never moves past the end of the
478                        // allocation, as per the loop bounds.
479                        element_ptr = unsafe { element_ptr.add(1) };
480                    }
481                    // Deallocate again.
482                    if mem::size_of::<T>() != 0 {
483                        // SAFETY: For non-ZST T, the tagged_ptr's non_zst_tagged_ptr union field is
484                        // active.
485                        let tagged_ptr = unsafe { v.tagged_ptr.non_zst_tagged_ptr };
486                        let tag = tagged_ptr.addr() & PTR_TAG_MASK;
487                        let untagged_ptr = tagged_ptr.map_addr(|tagged_ptr| tagged_ptr & !PTR_TAG_MASK);
488                        // SAFETY: untagged_ptr is non-null as T is not a ZST and len is != 0 when here.
489                        let untagged_ptr = unsafe { ptr::NonNull::new_unchecked(untagged_ptr) };
490                        if tag != PTR_TAG_MASK {
491                            // SAFETY: untagged_ptr has previously been obtained above from
492                            // FixedVecDataWithoutLen::try_allocate() as per the tag value and not
493                            // been deallocated since.
494                            unsafe { FixedVecDataWithoutLen::<T>::deallocate(untagged_ptr, len) };
495                        } else {
496                            // SAFETY: untagged_ptr has previously been obtained above from
497                            // FixedVecDataWithLen::try_allocate() as per the tag value and not been
498                            // deallocated since.
499                            unsafe { FixedVecDataWithLen::<T>::deallocate(untagged_ptr, len) };
500                        }
501                    }
502
503                    return Err(FixedVecNewFromFnError::FnError(e));
504                }
505            };
506            // SAFETY:
507            // - If T is a ZST, then data_ptr and hence element_ptr is ptr::dangling_mut(),
508            //   hence properly aligned and non-null.
509            // - Otherwise data_ptr has been obtained from either
510            //   FixedVecDataWithoutLen::data_ptr() or FixedVecDataWithLen::data_ptr() on an
511            //   allocation obtained from a prior successful
512            //   FixedVecDataWithoutLen::try_allocate() or
513            //   FixedVecDataWithLen::try_allocate() invoked with len respectively. Thus,
514            //   considering the loop bounds, element_ptr is valid for reads and writes and
515            //   is aligned.
516            unsafe { element_ptr.write(value) };
517            // SAFETY: Either T is a ZST, or element_ptr never moves past the end of the
518            // allocation, as per the loop bounds.
519            element_ptr = unsafe { element_ptr.add(1) };
520        }
521
522        Ok(mem::ManuallyDrop::into_inner(v))
523    }
524
525    /// Returns true if the [`FixedVec`] contains no elements.
526    pub fn is_empty(&self) -> bool {
527        if mem::size_of::<T>() == 0 {
528            // SAFETY: For ZST T, the tagged_ptr's zst_data_len union field is active.
529            (unsafe { self.tagged_ptr.zst_data_len }) == 0
530        } else {
531            // SAFETY: For non-ZST T, the tagged_ptr's non_zst_tagged_ptr union field is
532            // active.
533            (unsafe { self.tagged_ptr.non_zst_tagged_ptr }).is_null()
534        }
535    }
536
537    /// Returns the number of elements in the [`FixedVec`].
538    pub fn len(&self) -> usize {
539        if mem::size_of::<T>() == 0 {
540            // SAFETY: For ZST T, the tagged_ptr's zst_data_len union field is active.
541            unsafe { self.tagged_ptr.zst_data_len }
542        } else {
543            // SAFETY: For non-ZST T, the tagged_ptr's non_zst_tagged_ptr union field is
544            // active.
545            let tagged_ptr = unsafe { self.tagged_ptr.non_zst_tagged_ptr };
546            if tagged_ptr.is_null() {
547                0
548            } else {
549                let tag = tagged_ptr.addr() & PTR_TAG_MASK;
550                if tag != PTR_TAG_MASK {
551                    // The tag encodes the length.
552                    1usize << (BASE_LEN_LOG2 + tag as u32)
553                } else {
554                    // The length is stored at the allocated memory's head.
555                    let untagged_ptr = tagged_ptr.map_addr(|tagged_ptr| tagged_ptr & !PTR_TAG_MASK);
556                    // SAFETY: If the FixedVec had been empty, then tagged_ptr would have been null
557                    // in the branch condition above. As the FixedVec isn't empty, some memory must
558                    // have been allocated for it, and untagged_ptr points at that.
559                    let untagged_ptr = unsafe { ptr::NonNull::new_unchecked(untagged_ptr) };
560                    // SAFETY: untagged_ptr has previously been obtained from
561                    // FixedVecDataWithLen::try_allocate() as per the tag value and not deallocated
562                    // yet because self is still alive.
563                    unsafe { FixedVecDataWithLen::<T>::data_len(untagged_ptr) }
564                }
565            }
566        }
567    }
568
569    /// Extracts a slice containing the entire [`FixedVec`].
570    ///
571    /// Equivalent to `&s[..]`.
572    pub fn as_slice(&self) -> &[T] {
573        let (data_ptr, len) = if mem::size_of::<T>() == 0 {
574            // SAFETY: For ZST T, the tagged_ptr's zst_data_len union field is active.
575            let len = unsafe { self.tagged_ptr.zst_data_len };
576            (ptr::NonNull::dangling(), len)
577        } else {
578            // SAFETY: xFor non-ZST T, the tagged_ptr's non_zst_tagged_ptr union field is
579            // active.
580            let tagged_ptr = unsafe { self.tagged_ptr.non_zst_tagged_ptr };
581            if tagged_ptr.is_null() {
582                (ptr::NonNull::dangling(), 0)
583            } else {
584                let tag = tagged_ptr.addr() & PTR_TAG_MASK;
585                let untagged_ptr = tagged_ptr.map_addr(|tagged_ptr| tagged_ptr & !PTR_TAG_MASK);
586                // SAFETY: If the FixedVec had been empty, then tagged_ptr would have been null
587                // in the branch condition above. As the FixedVec isn't empty,
588                // some memory must have been allocated for it, and untagged_ptr
589                // points at that.
590                let untagged_ptr = unsafe { ptr::NonNull::new_unchecked(untagged_ptr) };
591                if tag != PTR_TAG_MASK {
592                    // The tag encodes the length and the memory contains only the data elements.
593                    let len = 1usize << (BASE_LEN_LOG2 + tag as u32);
594                    // SAFETY: untagged_ptr has previously been obtained from
595                    // FixedVecDataWithoutLen::try_allocate() as per the tag value and not been
596                    // deallocated yet because self is still alive.
597                    let data_ptr = unsafe { FixedVecDataWithoutLen::data_ptr(untagged_ptr) };
598                    (data_ptr, len)
599                } else {
600                    // SAFETY: untagged_ptr has previously been obtained from
601                    // FixedVecDataWithLen::try_allocate() as per the tag value and not been
602                    // deallocated yet because self is still alive.
603                    let len = unsafe { FixedVecDataWithLen::<T>::data_len(untagged_ptr) };
604                    // SAFETY: likewise.
605                    let data_ptr = unsafe { FixedVecDataWithLen::data_ptr(untagged_ptr) };
606                    (data_ptr, len)
607                }
608            }
609        };
610
611        // SAFETY:
612        // - If T is a ZST or the FixedVec is empty, the data_ptr is
613        //   ptr::dangling_mut().
614        // - Otherwise it's been obtained from either FixedVecDataWithoutLen::data_ptr()
615        //   or FixedVecDataWithLen::data_ptr() on an allocation obtained from a prior
616        //   successful FixedVecDataWithoutLen::try_allocate() or
617        //   FixedVecDataWithLen::try_allocate() invoked with len respectively,
618        //   therefore points at the to the beginning of a contiguously allocated
619        //   sequence of len properly aligned memory slots suitable for storing a `T`
620        //   each, and the total memory size does not exceed `isize::MAX`. All Ts have
621        //   been initialized.
622        // In either case, while the constructed slice is alive, it carries a borrow on
623        // self, hence is exclusive with any writes.
624        unsafe { slice::from_raw_parts(data_ptr.as_ptr(), len) }
625    }
626
627    /// Extracts a mutable slice of the entire vector.
628    ///
629    /// Equivalent to `&mut s[..]`.
630    pub fn as_mut_slice(&mut self) -> &mut [T] {
631        let (data_ptr, len) = if mem::size_of::<T>() == 0 {
632            // SAFETY: For ZST T, the tagged_ptr's zst_data_len union field is active.
633            let len = unsafe { self.tagged_ptr.zst_data_len };
634            (ptr::NonNull::dangling(), len)
635        } else {
636            // SAFETY: For non-ZST T, the tagged_ptr's non_zst_tagged_ptr union field is
637            // active.
638            let tagged_ptr = unsafe { self.tagged_ptr.non_zst_tagged_ptr };
639            if tagged_ptr.is_null() {
640                (ptr::NonNull::dangling(), 0)
641            } else {
642                let tag = tagged_ptr.addr() & PTR_TAG_MASK;
643                let untagged_ptr = tagged_ptr.map_addr(|tagged_ptr| tagged_ptr & !PTR_TAG_MASK);
644                // SAFETY: If the FixedVec had been empty, then tagged_ptr would have been null
645                // in the branch condition above. As the FixedVec isn't empty,
646                // some memory must have been allocated for it, and untagged_ptr
647                // points at that.
648                let untagged_ptr = unsafe { ptr::NonNull::new_unchecked(untagged_ptr) };
649                if tag != PTR_TAG_MASK {
650                    // The tag encodes the length and the memory contains only the data elements.
651                    let len = 1usize << (BASE_LEN_LOG2 + tag as u32);
652                    // SAFETY: untagged_ptr has previously been obtained from
653                    // FixedVecDataWithoutLen::try_allocate() as per the tag value and not been
654                    // deallocated yet because self is still alive.
655                    let data_ptr = unsafe { FixedVecDataWithoutLen::data_ptr(untagged_ptr) };
656                    (data_ptr, len)
657                } else {
658                    // SAFETY: untagged_ptr has previously been obtained from
659                    // FixedVecDataWithLen::try_allocate() as per the tag value and not been
660                    // deallocated yet because self is still alive.
661                    let len = unsafe { FixedVecDataWithLen::<T>::data_len(untagged_ptr) };
662                    // SAFETY: likewise.
663                    let data_ptr = unsafe { FixedVecDataWithLen::data_ptr(untagged_ptr) };
664                    (data_ptr, len)
665                }
666            }
667        };
668
669        // SAFETY:
670        // - If T is a ZST or the FixedVec is empty, the data_ptr is
671        //   ptr::dangling_mut().
672        // - Otherwise it's been obtained from either FixedVecDataWithoutLen::data_ptr()
673        //   or FixedVecDataWithLen::data_ptr() on an allocation obtained from a prior
674        //   successful FixedVecDataWithoutLen::try_allocate() or
675        //   FixedVecDataWithLen::try_allocate() invoked with len respectively,
676        //   therefore points at the to the beginning of a contiguously allocated
677        //   sequence of len properly aligned memory slots suitable for storing a `T`
678        //   each, and the total memory size does not exceed `isize::MAX`. All Ts have
679        //   been initialized.
680        // In either case, while the constructed slice is alive, all accesses to the
681        // backing memory will be made exclusively through it, because it
682        // carries a borrow on self.
683        unsafe { slice::from_raw_parts_mut(data_ptr.as_ptr(), len) }
684    }
685}
686
687impl<T: Sized, const BASE_LEN_LOG2: u32> Drop for FixedVec<T, BASE_LEN_LOG2> {
688    fn drop(&mut self) {
689        if mem::size_of::<T>() == 0 {
690            // SAFETY: For ZST T, the tagged_ptr's zst_data_len union field is active.
691            let len = unsafe { self.tagged_ptr.zst_data_len };
692            let data_ptr = ptr::dangling_mut::<T>();
693            let mut element_ptr = data_ptr;
694            for _ in 0..len {
695                // SAFETY: T is a ZST, and element_ptr is ptr::dangling_mut(), so aligned and
696                // non-null.
697                unsafe { element_ptr.drop_in_place() };
698                // SAFETY: T is a ZST, so this is a nop.
699                element_ptr = unsafe { element_ptr.add(1) };
700            }
701        } else {
702            // SAFETY: For non-ZST T, the tagged_ptr's non_zst_tagged_ptr union field is
703            // active.
704            let tagged_ptr = unsafe { self.tagged_ptr.non_zst_tagged_ptr };
705            if !tagged_ptr.is_null() {
706                let tag = tagged_ptr.addr() & PTR_TAG_MASK;
707                let untagged_ptr = tagged_ptr.map_addr(|tagged_ptr| tagged_ptr & !PTR_TAG_MASK);
708                // SAFETY: If the FixedVec had been empty, then tagged_ptr would have been null
709                // in the branch condition above. As the FixedVec isn't empty,
710                // some memory must have been allocated for it, and untagged_ptr
711                // points at that.
712                let untagged_ptr = unsafe { ptr::NonNull::new_unchecked(untagged_ptr) };
713                let (data_ptr, len) = if tag != PTR_TAG_MASK {
714                    // The tag encodes the length and the memory contains only the data elements.
715                    let len = 1usize << (BASE_LEN_LOG2 + tag as u32);
716                    // SAFETY: untagged_ptr has previously been obtained from
717                    // FixedVecDataWithoutLen::try_allocate() as per the tag value and not been
718                    // deallocated already because self is only about to get dropped now.
719                    let data_ptr = unsafe { FixedVecDataWithoutLen::<T>::data_ptr(untagged_ptr) };
720                    (data_ptr, len)
721                } else {
722                    // SAFETY: untagged_ptr has previously been obtained from
723                    // FixedVecDataWithLen::try_allocate() as per the tag value and not been
724                    // deallocated already because self is only about to get dropped now.
725                    let len = unsafe { FixedVecDataWithLen::<T>::data_len(untagged_ptr) };
726                    // SAFETY: likewise.
727                    let data_ptr = unsafe { FixedVecDataWithLen::<T>::data_ptr(untagged_ptr) };
728                    (data_ptr, len)
729                };
730
731                let mut element_ptr = data_ptr;
732                for _ in 0..len {
733                    // - SAFETY: data_ptr has been obtained from either
734                    //   FixedVecDataWithoutLen::data_ptr() or FixedVecDataWithLen::data_ptr() on an
735                    //   allocation obtained from a prior successful
736                    //   FixedVecDataWithoutLen::try_allocate() or
737                    //   FixedVecDataWithLen::try_allocate() invoked with len respectively. Thus,
738                    //   considering the loop bounds, element_ptr is valid for reads and writes, is
739                    //   aligned and points at an initialized T.
740                    unsafe { element_ptr.drop_in_place() };
741                    // SAFETY: element_ptr never moves past the end of the allocation,
742                    // as per the loop bounds.
743                    element_ptr = unsafe { element_ptr.add(1) };
744                }
745
746                if tag != PTR_TAG_MASK {
747                    // SAFETY: untagged_ptr has previously been obtained from
748                    // FixedVecDataWithoutLen::try_allocate() as per the tag value and not been
749                    // deallocated already because self is only about to get dropped now.
750                    unsafe { FixedVecDataWithoutLen::<T>::deallocate(untagged_ptr, len) };
751                } else {
752                    // SAFETY: untagged_ptr has previously been obtained from
753                    // FixedVecDataWithLen::try_allocate() as per the tag value and not been
754                    // deallocated already because self is only about to get dropped now.
755                    unsafe { FixedVecDataWithLen::<T>::deallocate(untagged_ptr, len) };
756                }
757            }
758        }
759    }
760}
761
762impl<T: Sized + Default, const BASE_LEN_LOG2: u32> FixedVec<T, BASE_LEN_LOG2> {
763    /// Instantiate a [`FixedVec`] of specified length and default-initialize
764    /// its elements.
765    ///
766    /// Instantiate a [`FixedVec`] of length `len`, and initialize all its
767    /// elements with `T::default()`.
768    ///
769    /// # Arguments:
770    ///
771    /// * `len` - The number of elements the instantiated [`FixedVec`] shall
772    ///   contain.
773    pub fn new_with_default(len: usize) -> Result<Self, FixedVecMemoryAllocationFailure> {
774        Self::new_from_fn(len, |_| -> Result<T, convert::Infallible> { Ok(T::default()) })
775            .map_err(FixedVecMemoryAllocationFailure::from)
776    }
777}
778
779impl<T: Sized + Clone, const BASE_LEN_LOG2: u32> FixedVec<T, BASE_LEN_LOG2> {
780    /// Instantiate a [`FixedVec`] of specified length and initialize all its
781    /// elements with a given value.
782    ///
783    /// Instantiate a [`FixedVec`] of length `len`, and initialize its elements
784    /// with `value`.
785    ///
786    /// # Arguments:
787    ///
788    /// * `len` - The number of elements the instantiated [`FixedVec`] shall
789    ///   contain.
790    /// * `value` - The element initialization value.
791    pub fn new_with_value(len: usize, value: T) -> Result<Self, FixedVecMemoryAllocationFailure> {
792        Self::new_from_fn(len, |_| -> Result<T, convert::Infallible> { Ok(value.clone()) })
793            .map_err(FixedVecMemoryAllocationFailure::from)
794    }
795}
796
797impl<T: Sized, const BASE_LEN_LOG2: u32> ops::Deref for FixedVec<T, BASE_LEN_LOG2> {
798    type Target = [T];
799    fn deref(&self) -> &Self::Target {
800        self.as_slice()
801    }
802}
803
804impl<T: Sized, const BASE_LEN_LOG2: u32> ops::DerefMut for FixedVec<T, BASE_LEN_LOG2> {
805    fn deref_mut(&mut self) -> &mut Self::Target {
806        self.as_mut_slice()
807    }
808}
809
810impl<T: Sized, const BASE_LEN_LOG2: u32> convert::AsRef<[T]> for FixedVec<T, BASE_LEN_LOG2> {
811    fn as_ref(&self) -> &[T] {
812        self
813    }
814}
815
816impl<T: Sized, const BASE_LEN_LOG2: u32> convert::AsMut<[T]> for FixedVec<T, BASE_LEN_LOG2> {
817    fn as_mut(&mut self) -> &mut [T] {
818        self
819    }
820}
821
822impl<T: Sized, I: slice::SliceIndex<[T]>, const BASE_LEN_LOG2: u32> ops::Index<I> for FixedVec<T, BASE_LEN_LOG2> {
823    type Output = I::Output;
824
825    fn index(&self, index: I) -> &Self::Output {
826        &ops::Deref::deref(self)[index]
827    }
828}
829
830impl<T: Sized, I: slice::SliceIndex<[T]>, const BASE_LEN_LOG2: u32> ops::IndexMut<I> for FixedVec<T, BASE_LEN_LOG2> {
831    fn index_mut(&mut self, index: I) -> &mut Self::Output {
832        &mut ops::DerefMut::deref_mut(self)[index]
833    }
834}
835
836impl<T: Sized, const BASE_LEN_LOG2: u32> Default for FixedVec<T, BASE_LEN_LOG2> {
837    fn default() -> Self {
838        Self::new_empty()
839    }
840}
841
842impl<T: Sized + Clone, const BASE_LEN_LOG2: u32> Clone for FixedVec<T, BASE_LEN_LOG2> {
843    fn clone(&self) -> Self {
844        Self::new_from_fn(self.len(), |i| -> Result<T, convert::Infallible> {
845            Ok((*self)[i].clone())
846        })
847        .unwrap()
848    }
849}
850
851impl<'a, T: Sized + Clone, const BASE_LEN_LOG2: u32> iter::IntoIterator for &'a FixedVec<T, BASE_LEN_LOG2> {
852    type Item = &'a T;
853    type IntoIter = slice::Iter<'a, T>;
854
855    fn into_iter(self) -> Self::IntoIter {
856        (**self).iter()
857    }
858}
859
860impl<'a, T: Sized + Clone, const BASE_LEN_LOG2: u32> iter::IntoIterator for &'a mut FixedVec<T, BASE_LEN_LOG2> {
861    type Item = &'a mut T;
862    type IntoIter = slice::IterMut<'a, T>;
863
864    fn into_iter(self) -> Self::IntoIter {
865        (**self).iter_mut()
866    }
867}
868
869impl<T: Sized + cmp::PartialEq, const BASE_LEN_LOG2: u32> cmp::PartialEq for FixedVec<T, BASE_LEN_LOG2> {
870    fn eq(&self, other: &Self) -> bool {
871        self.as_slice().eq(other.as_slice())
872    }
873}
874
875impl<T: Sized + cmp::Eq, const BASE_LEN_LOG2: u32> cmp::Eq for FixedVec<T, BASE_LEN_LOG2> {}
876
877// SAFETY: if T is Send, then so is the FixedVec.
878unsafe impl<T: Sized + marker::Send, const BASE_LEN_LOG2: u32> marker::Send for FixedVec<T, BASE_LEN_LOG2> {}
879
880// SAFETY: if T is Sync, then so is the FixedVec.
881unsafe impl<T: Sized + marker::Sync, const BASE_LEN_LOG2: u32> marker::Sync for FixedVec<T, BASE_LEN_LOG2> {}
882
883impl<T: Sized + fmt::Debug, const BASE_LEN_LOG2: u32> fmt::Debug for FixedVec<T, BASE_LEN_LOG2> {
884    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
885        fmt::Debug::fmt(&**self, f)
886    }
887}
888
889#[cfg(feature = "zeroize")]
890impl<T: Sized + zeroize::Zeroize, const BASE_LEN_LOG2: u32> zeroize::Zeroize for FixedVec<T, BASE_LEN_LOG2> {
891    fn zeroize(&mut self) {
892        for element in self.iter_mut() {
893            element.zeroize();
894        }
895    }
896}
897
898#[cfg(feature = "zeroize")]
899impl<T: Sized + zeroize::ZeroizeOnDrop, const BASE_LEN_LOG2: u32> zeroize::ZeroizeOnDrop
900    for FixedVec<T, BASE_LEN_LOG2>
901{
902}
903
904#[cfg(test)]
905fn test_one<T: Sized + Default + Clone + cmp::Eq + fmt::Debug, const BASE_LEN_LOG2: u32>(test_value: T) {
906    let mut v_empty = FixedVec::<T, BASE_LEN_LOG2>::new_empty();
907    assert!(v_empty.is_empty());
908    assert_eq!(v_empty.len(), 0);
909    assert_eq!(v_empty.iter().count(), 0);
910    assert_eq!(v_empty.iter_mut().count(), 0);
911
912    for len in [
913        0usize,
914        (1usize << BASE_LEN_LOG2) - 1,
915        (1usize << BASE_LEN_LOG2),
916        (1usize << BASE_LEN_LOG2) + 1,
917        1usize << (BASE_LEN_LOG2 + PTR_TAG_MASK as u32 - 1),
918        1usize << (BASE_LEN_LOG2 + PTR_TAG_MASK as u32),
919        1usize << (BASE_LEN_LOG2 + PTR_TAG_MASK as u32 + 1),
920    ] {
921        let mut v0 = FixedVec::<T, BASE_LEN_LOG2>::new_with_default(len).unwrap();
922        assert_eq!(v0.is_empty(), len == 0);
923        assert_eq!(v0.len(), len);
924        assert_eq!(v0.iter().count(), len);
925        assert_eq!(v0.iter_mut().count(), len);
926        for element in v0.iter() {
927            assert_eq!(*element, T::default());
928        }
929        for element in v0.iter_mut() {
930            *element = test_value.clone();
931        }
932
933        let mut v1 = FixedVec::<T, BASE_LEN_LOG2>::new_with_value(len, test_value.clone()).unwrap();
934        assert_eq!(v1.is_empty(), len == 0);
935        assert_eq!(v1.len(), len);
936        assert_eq!(v1.iter().count(), len);
937        assert_eq!(v1.iter_mut().count(), len);
938        for element in v1.iter() {
939            assert_eq!(*element, test_value.clone());
940        }
941
942        assert_eq!(v0.as_slice(), v1.as_slice());
943
944        assert!(
945            len == 0
946                || matches!(
947                    FixedVec::<T, BASE_LEN_LOG2>::new_from_fn(len, |i| {
948                        if i != len - 1 { Ok(T::default()) } else { Err(()) }
949                    },),
950                    Err(FixedVecNewFromFnError::FnError(()))
951                )
952        );
953    }
954}
955
956#[test]
957fn fixed_vec_u32_0() {
958    test_one::<u32, 0>(42);
959}
960
961#[test]
962fn fixed_vec_u32_2() {
963    test_one::<u32, 2>(42);
964}
965
966#[cfg(test)]
967use core::sync;
968
969#[cfg(test)]
970static TEST_ZST_INSTANCES: sync::atomic::AtomicUsize = sync::atomic::AtomicUsize::new(0);
971
972#[cfg(test)]
973#[derive(Debug, PartialEq, Eq)]
974struct TestZST;
975
976#[cfg(test)]
977impl Default for TestZST {
978    fn default() -> Self {
979        TEST_ZST_INSTANCES.fetch_add(1, sync::atomic::Ordering::Relaxed);
980        TestZST
981    }
982}
983
984#[cfg(test)]
985impl Clone for TestZST {
986    fn clone(&self) -> Self {
987        Self::default()
988    }
989}
990
991#[cfg(test)]
992impl Drop for TestZST {
993    fn drop(&mut self) {
994        TEST_ZST_INSTANCES.fetch_sub(1, sync::atomic::Ordering::Relaxed);
995    }
996}
997
998#[test]
999fn fixed_vec_zst() {
1000    fn _fixed_vec_zst() {
1001        test_one::<TestZST, 0>(TestZST::default());
1002        test_one::<TestZST, 2>(TestZST::default());
1003    }
1004    _fixed_vec_zst();
1005    assert_eq!(TEST_ZST_INSTANCES.load(sync::atomic::Ordering::Relaxed), 0);
1006}