// 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::<T>() <= isize::MAX`. pub struct ArrayLayout<T> { len: usize, _phantom: PhantomData<fn() -> T>, } impl<T> Clone for ArrayLayout<T> { fn clone(&self) -> Self { *self } } impl<T> Copy for ArrayLayout<T> {} const ISIZE_MAX: usize = isize::MAX as usize; impl<T> ArrayLayout<T> { /// Creates a new layout for `[T; 0]`. pub const fn empty() -> Self { // INVARIANT: `0 * size_of::<T>() <= isize::MAX`. Self { len: 0, _phantom: PhantomData, } } /// Creates a new layout for `[T; len]`. /// /// # Errors /// /// When `len * size_of::<T>()` overflows or when `len * size_of::<T>() > isize::MAX`. /// /// # Examples /// /// ``` /// # use kernel::alloc::layout::{ArrayLayout, LayoutError}; /// let layout = ArrayLayout::<i32>::new(15)?; /// assert_eq!(layout.len(), 15); /// /// // Errors because `len * size_of::<T>()` overflows. /// let layout = ArrayLayout::<i32>::new(isize::MAX as usize); /// assert!(layout.is_err()); /// /// // Errors because `len * size_of::<i32>() > isize::MAX`, /// // even though `len < isize::MAX`. /// let layout = ArrayLayout::<i32>::new(isize::MAX as usize / 2); /// assert!(layout.is_err()); /// /// # Ok::<(), Error>(()) /// ``` pub const fn new(len: usize) -> Result<Self, LayoutError> { match len.checked_mul(core::mem::size_of::<T>()) { Some(size) if size <= ISIZE_MAX => { // INVARIANT: We checked above that `len * size_of::<T>() <= 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::<T>() <= isize::MAX` is true. pub unsafe fn new_unchecked(len: usize) -> Self { // INVARIANT: By the safety requirements of this function // `len * size_of::<T>() <= 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<T> From<ArrayLayout<T>> for Layout { fn from(value: ArrayLayout<T>) -> Self { let res = Layout::array::<T>(value.len); // SAFETY: By the type invariant of `ArrayLayout` we have // `len * size_of::<T>() <= isize::MAX` and thus the result must be `Ok`. unsafe { res.unwrap_unchecked() } } }