1*9e7bbfa1SBenno Lossin // SPDX-License-Identifier: GPL-2.0 2*9e7bbfa1SBenno Lossin 3*9e7bbfa1SBenno Lossin //! Memory layout. 4*9e7bbfa1SBenno Lossin //! 5*9e7bbfa1SBenno Lossin //! Custom layout types extending or improving [`Layout`]. 6*9e7bbfa1SBenno Lossin 7*9e7bbfa1SBenno Lossin use core::{alloc::Layout, marker::PhantomData}; 8*9e7bbfa1SBenno Lossin 9*9e7bbfa1SBenno Lossin /// Error when constructing an [`ArrayLayout`]. 10*9e7bbfa1SBenno Lossin pub struct LayoutError; 11*9e7bbfa1SBenno Lossin 12*9e7bbfa1SBenno Lossin /// A layout for an array `[T; n]`. 13*9e7bbfa1SBenno Lossin /// 14*9e7bbfa1SBenno Lossin /// # Invariants 15*9e7bbfa1SBenno Lossin /// 16*9e7bbfa1SBenno Lossin /// - `len * size_of::<T>() <= isize::MAX`. 17*9e7bbfa1SBenno Lossin pub struct ArrayLayout<T> { 18*9e7bbfa1SBenno Lossin len: usize, 19*9e7bbfa1SBenno Lossin _phantom: PhantomData<fn() -> T>, 20*9e7bbfa1SBenno Lossin } 21*9e7bbfa1SBenno Lossin 22*9e7bbfa1SBenno Lossin impl<T> Clone for ArrayLayout<T> { 23*9e7bbfa1SBenno Lossin fn clone(&self) -> Self { 24*9e7bbfa1SBenno Lossin *self 25*9e7bbfa1SBenno Lossin } 26*9e7bbfa1SBenno Lossin } 27*9e7bbfa1SBenno Lossin impl<T> Copy for ArrayLayout<T> {} 28*9e7bbfa1SBenno Lossin 29*9e7bbfa1SBenno Lossin const ISIZE_MAX: usize = isize::MAX as usize; 30*9e7bbfa1SBenno Lossin 31*9e7bbfa1SBenno Lossin impl<T> ArrayLayout<T> { 32*9e7bbfa1SBenno Lossin /// Creates a new layout for `[T; 0]`. 33*9e7bbfa1SBenno Lossin pub const fn empty() -> Self { 34*9e7bbfa1SBenno Lossin // INVARIANT: `0 * size_of::<T>() <= isize::MAX`. 35*9e7bbfa1SBenno Lossin Self { 36*9e7bbfa1SBenno Lossin len: 0, 37*9e7bbfa1SBenno Lossin _phantom: PhantomData, 38*9e7bbfa1SBenno Lossin } 39*9e7bbfa1SBenno Lossin } 40*9e7bbfa1SBenno Lossin 41*9e7bbfa1SBenno Lossin /// Creates a new layout for `[T; len]`. 42*9e7bbfa1SBenno Lossin /// 43*9e7bbfa1SBenno Lossin /// # Errors 44*9e7bbfa1SBenno Lossin /// 45*9e7bbfa1SBenno Lossin /// When `len * size_of::<T>()` overflows or when `len * size_of::<T>() > isize::MAX`. 46*9e7bbfa1SBenno Lossin pub const fn new(len: usize) -> Result<Self, LayoutError> { 47*9e7bbfa1SBenno Lossin match len.checked_mul(core::mem::size_of::<T>()) { 48*9e7bbfa1SBenno Lossin Some(len) if len <= ISIZE_MAX => { 49*9e7bbfa1SBenno Lossin // INVARIANT: We checked above that `len * size_of::<T>() <= isize::MAX`. 50*9e7bbfa1SBenno Lossin Ok(Self { 51*9e7bbfa1SBenno Lossin len, 52*9e7bbfa1SBenno Lossin _phantom: PhantomData, 53*9e7bbfa1SBenno Lossin }) 54*9e7bbfa1SBenno Lossin } 55*9e7bbfa1SBenno Lossin _ => Err(LayoutError), 56*9e7bbfa1SBenno Lossin } 57*9e7bbfa1SBenno Lossin } 58*9e7bbfa1SBenno Lossin 59*9e7bbfa1SBenno Lossin /// Creates a new layout for `[T; len]`. 60*9e7bbfa1SBenno Lossin /// 61*9e7bbfa1SBenno Lossin /// # Safety 62*9e7bbfa1SBenno Lossin /// 63*9e7bbfa1SBenno Lossin /// `len` must be a value, for which `len * size_of::<T>() <= isize::MAX` is true. 64*9e7bbfa1SBenno Lossin pub unsafe fn new_unchecked(len: usize) -> Self { 65*9e7bbfa1SBenno Lossin // INVARIANT: By the safety requirements of this function 66*9e7bbfa1SBenno Lossin // `len * size_of::<T>() <= isize::MAX`. 67*9e7bbfa1SBenno Lossin Self { 68*9e7bbfa1SBenno Lossin len, 69*9e7bbfa1SBenno Lossin _phantom: PhantomData, 70*9e7bbfa1SBenno Lossin } 71*9e7bbfa1SBenno Lossin } 72*9e7bbfa1SBenno Lossin 73*9e7bbfa1SBenno Lossin /// Returns the number of array elements represented by this layout. 74*9e7bbfa1SBenno Lossin pub const fn len(&self) -> usize { 75*9e7bbfa1SBenno Lossin self.len 76*9e7bbfa1SBenno Lossin } 77*9e7bbfa1SBenno Lossin 78*9e7bbfa1SBenno Lossin /// Returns `true` when no array elements are represented by this layout. 79*9e7bbfa1SBenno Lossin pub const fn is_empty(&self) -> bool { 80*9e7bbfa1SBenno Lossin self.len == 0 81*9e7bbfa1SBenno Lossin } 82*9e7bbfa1SBenno Lossin } 83*9e7bbfa1SBenno Lossin 84*9e7bbfa1SBenno Lossin impl<T> From<ArrayLayout<T>> for Layout { 85*9e7bbfa1SBenno Lossin fn from(value: ArrayLayout<T>) -> Self { 86*9e7bbfa1SBenno Lossin let res = Layout::array::<T>(value.len); 87*9e7bbfa1SBenno Lossin // SAFETY: By the type invariant of `ArrayLayout` we have 88*9e7bbfa1SBenno Lossin // `len * size_of::<T>() <= isize::MAX` and thus the result must be `Ok`. 89*9e7bbfa1SBenno Lossin unsafe { res.unwrap_unchecked() } 90*9e7bbfa1SBenno Lossin } 91*9e7bbfa1SBenno Lossin } 92