19e7bbfa1SBenno Lossin // SPDX-License-Identifier: GPL-2.0 29e7bbfa1SBenno Lossin 39e7bbfa1SBenno Lossin //! Memory layout. 49e7bbfa1SBenno Lossin //! 59e7bbfa1SBenno Lossin //! Custom layout types extending or improving [`Layout`]. 69e7bbfa1SBenno Lossin 79e7bbfa1SBenno Lossin use core::{alloc::Layout, marker::PhantomData}; 89e7bbfa1SBenno Lossin 99e7bbfa1SBenno Lossin /// Error when constructing an [`ArrayLayout`]. 109e7bbfa1SBenno Lossin pub struct LayoutError; 119e7bbfa1SBenno Lossin 129e7bbfa1SBenno Lossin /// A layout for an array `[T; n]`. 139e7bbfa1SBenno Lossin /// 149e7bbfa1SBenno Lossin /// # Invariants 159e7bbfa1SBenno Lossin /// 169e7bbfa1SBenno Lossin /// - `len * size_of::<T>() <= isize::MAX`. 179e7bbfa1SBenno Lossin pub struct ArrayLayout<T> { 189e7bbfa1SBenno Lossin len: usize, 199e7bbfa1SBenno Lossin _phantom: PhantomData<fn() -> T>, 209e7bbfa1SBenno Lossin } 219e7bbfa1SBenno Lossin 229e7bbfa1SBenno Lossin impl<T> Clone for ArrayLayout<T> { 239e7bbfa1SBenno Lossin fn clone(&self) -> Self { 249e7bbfa1SBenno Lossin *self 259e7bbfa1SBenno Lossin } 269e7bbfa1SBenno Lossin } 279e7bbfa1SBenno Lossin impl<T> Copy for ArrayLayout<T> {} 289e7bbfa1SBenno Lossin 299e7bbfa1SBenno Lossin const ISIZE_MAX: usize = isize::MAX as usize; 309e7bbfa1SBenno Lossin 319e7bbfa1SBenno Lossin impl<T> ArrayLayout<T> { 329e7bbfa1SBenno Lossin /// Creates a new layout for `[T; 0]`. 339e7bbfa1SBenno Lossin pub const fn empty() -> Self { 349e7bbfa1SBenno Lossin // INVARIANT: `0 * size_of::<T>() <= isize::MAX`. 359e7bbfa1SBenno Lossin Self { 369e7bbfa1SBenno Lossin len: 0, 379e7bbfa1SBenno Lossin _phantom: PhantomData, 389e7bbfa1SBenno Lossin } 399e7bbfa1SBenno Lossin } 409e7bbfa1SBenno Lossin 419e7bbfa1SBenno Lossin /// Creates a new layout for `[T; len]`. 429e7bbfa1SBenno Lossin /// 439e7bbfa1SBenno Lossin /// # Errors 449e7bbfa1SBenno Lossin /// 459e7bbfa1SBenno Lossin /// When `len * size_of::<T>()` overflows or when `len * size_of::<T>() > isize::MAX`. 469e7bbfa1SBenno Lossin pub const fn new(len: usize) -> Result<Self, LayoutError> { 479e7bbfa1SBenno Lossin match len.checked_mul(core::mem::size_of::<T>()) { 48*b7ed2b6fSAsahi Lina Some(size) if size <= ISIZE_MAX => { 499e7bbfa1SBenno Lossin // INVARIANT: We checked above that `len * size_of::<T>() <= isize::MAX`. 509e7bbfa1SBenno Lossin Ok(Self { 519e7bbfa1SBenno Lossin len, 529e7bbfa1SBenno Lossin _phantom: PhantomData, 539e7bbfa1SBenno Lossin }) 549e7bbfa1SBenno Lossin } 559e7bbfa1SBenno Lossin _ => Err(LayoutError), 569e7bbfa1SBenno Lossin } 579e7bbfa1SBenno Lossin } 589e7bbfa1SBenno Lossin 599e7bbfa1SBenno Lossin /// Creates a new layout for `[T; len]`. 609e7bbfa1SBenno Lossin /// 619e7bbfa1SBenno Lossin /// # Safety 629e7bbfa1SBenno Lossin /// 639e7bbfa1SBenno Lossin /// `len` must be a value, for which `len * size_of::<T>() <= isize::MAX` is true. 649e7bbfa1SBenno Lossin pub unsafe fn new_unchecked(len: usize) -> Self { 659e7bbfa1SBenno Lossin // INVARIANT: By the safety requirements of this function 669e7bbfa1SBenno Lossin // `len * size_of::<T>() <= isize::MAX`. 679e7bbfa1SBenno Lossin Self { 689e7bbfa1SBenno Lossin len, 699e7bbfa1SBenno Lossin _phantom: PhantomData, 709e7bbfa1SBenno Lossin } 719e7bbfa1SBenno Lossin } 729e7bbfa1SBenno Lossin 739e7bbfa1SBenno Lossin /// Returns the number of array elements represented by this layout. 749e7bbfa1SBenno Lossin pub const fn len(&self) -> usize { 759e7bbfa1SBenno Lossin self.len 769e7bbfa1SBenno Lossin } 779e7bbfa1SBenno Lossin 789e7bbfa1SBenno Lossin /// Returns `true` when no array elements are represented by this layout. 799e7bbfa1SBenno Lossin pub const fn is_empty(&self) -> bool { 809e7bbfa1SBenno Lossin self.len == 0 819e7bbfa1SBenno Lossin } 829e7bbfa1SBenno Lossin } 839e7bbfa1SBenno Lossin 849e7bbfa1SBenno Lossin impl<T> From<ArrayLayout<T>> for Layout { 859e7bbfa1SBenno Lossin fn from(value: ArrayLayout<T>) -> Self { 869e7bbfa1SBenno Lossin let res = Layout::array::<T>(value.len); 879e7bbfa1SBenno Lossin // SAFETY: By the type invariant of `ArrayLayout` we have 889e7bbfa1SBenno Lossin // `len * size_of::<T>() <= isize::MAX` and thus the result must be `Ok`. 899e7bbfa1SBenno Lossin unsafe { res.unwrap_unchecked() } 909e7bbfa1SBenno Lossin } 919e7bbfa1SBenno Lossin } 92