// SPDX-License-Identifier: GPL-2.0 //! Memory layout. //! //! Custom layout types extending or improving [`Layout`]. use core::{alloc::Layout, marker::PhantomData}; /// Error when constructing an [`ArrayLayout`]. pub struct LayoutError; /// A layout for an array `[T; n]`. /// /// # Invariants /// /// - `len * size_of::() <= isize::MAX`. pub struct ArrayLayout { len: usize, _phantom: PhantomData T>, } impl Clone for ArrayLayout { fn clone(&self) -> Self { *self } } impl Copy for ArrayLayout {} const ISIZE_MAX: usize = isize::MAX as usize; impl ArrayLayout { /// Creates a new layout for `[T; 0]`. pub const fn empty() -> Self { // INVARIANT: `0 * size_of::() <= isize::MAX`. Self { len: 0, _phantom: PhantomData, } } /// Creates a new layout for `[T; len]`. /// /// # Errors /// /// When `len * size_of::()` overflows or when `len * size_of::() > isize::MAX`. pub const fn new(len: usize) -> Result { match len.checked_mul(core::mem::size_of::()) { Some(size) if size <= ISIZE_MAX => { // INVARIANT: We checked above that `len * size_of::() <= isize::MAX`. Ok(Self { len, _phantom: PhantomData, }) } _ => Err(LayoutError), } } /// Creates a new layout for `[T; len]`. /// /// # Safety /// /// `len` must be a value, for which `len * size_of::() <= isize::MAX` is true. pub unsafe fn new_unchecked(len: usize) -> Self { // INVARIANT: By the safety requirements of this function // `len * size_of::() <= isize::MAX`. Self { len, _phantom: PhantomData, } } /// Returns the number of array elements represented by this layout. pub const fn len(&self) -> usize { self.len } /// Returns `true` when no array elements are represented by this layout. pub const fn is_empty(&self) -> bool { self.len == 0 } } impl From> for Layout { fn from(value: ArrayLayout) -> Self { let res = Layout::array::(value.len); // SAFETY: By the type invariant of `ArrayLayout` we have // `len * size_of::() <= isize::MAX` and thus the result must be `Ok`. unsafe { res.unwrap_unchecked() } } }