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> { clone(&self) -> Self239e7bbfa1SBenno 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]`. empty() -> Self339e7bbfa1SBenno 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`. 46*91da5a24SJimmy Ostler /// 47*91da5a24SJimmy Ostler /// # Examples 48*91da5a24SJimmy Ostler /// 49*91da5a24SJimmy Ostler /// ``` 50*91da5a24SJimmy Ostler /// # use kernel::alloc::layout::{ArrayLayout, LayoutError}; 51*91da5a24SJimmy Ostler /// let layout = ArrayLayout::<i32>::new(15)?; 52*91da5a24SJimmy Ostler /// assert_eq!(layout.len(), 15); 53*91da5a24SJimmy Ostler /// 54*91da5a24SJimmy Ostler /// // Errors because `len * size_of::<T>()` overflows. 55*91da5a24SJimmy Ostler /// let layout = ArrayLayout::<i32>::new(isize::MAX as usize); 56*91da5a24SJimmy Ostler /// assert!(layout.is_err()); 57*91da5a24SJimmy Ostler /// 58*91da5a24SJimmy Ostler /// // Errors because `len * size_of::<i32>() > isize::MAX`, 59*91da5a24SJimmy Ostler /// // even though `len < isize::MAX`. 60*91da5a24SJimmy Ostler /// let layout = ArrayLayout::<i32>::new(isize::MAX as usize / 2); 61*91da5a24SJimmy Ostler /// assert!(layout.is_err()); 62*91da5a24SJimmy Ostler /// 63*91da5a24SJimmy Ostler /// # Ok::<(), Error>(()) 64*91da5a24SJimmy Ostler /// ``` new(len: usize) -> Result<Self, LayoutError>659e7bbfa1SBenno Lossin pub const fn new(len: usize) -> Result<Self, LayoutError> { 669e7bbfa1SBenno Lossin match len.checked_mul(core::mem::size_of::<T>()) { 67b7ed2b6fSAsahi Lina Some(size) if size <= ISIZE_MAX => { 689e7bbfa1SBenno Lossin // INVARIANT: We checked above that `len * size_of::<T>() <= isize::MAX`. 699e7bbfa1SBenno Lossin Ok(Self { 709e7bbfa1SBenno Lossin len, 719e7bbfa1SBenno Lossin _phantom: PhantomData, 729e7bbfa1SBenno Lossin }) 739e7bbfa1SBenno Lossin } 749e7bbfa1SBenno Lossin _ => Err(LayoutError), 759e7bbfa1SBenno Lossin } 769e7bbfa1SBenno Lossin } 779e7bbfa1SBenno Lossin 789e7bbfa1SBenno Lossin /// Creates a new layout for `[T; len]`. 799e7bbfa1SBenno Lossin /// 809e7bbfa1SBenno Lossin /// # Safety 819e7bbfa1SBenno Lossin /// 829e7bbfa1SBenno Lossin /// `len` must be a value, for which `len * size_of::<T>() <= isize::MAX` is true. new_unchecked(len: usize) -> Self839e7bbfa1SBenno Lossin pub unsafe fn new_unchecked(len: usize) -> Self { 849e7bbfa1SBenno Lossin // INVARIANT: By the safety requirements of this function 859e7bbfa1SBenno Lossin // `len * size_of::<T>() <= isize::MAX`. 869e7bbfa1SBenno Lossin Self { 879e7bbfa1SBenno Lossin len, 889e7bbfa1SBenno Lossin _phantom: PhantomData, 899e7bbfa1SBenno Lossin } 909e7bbfa1SBenno Lossin } 919e7bbfa1SBenno Lossin 929e7bbfa1SBenno Lossin /// Returns the number of array elements represented by this layout. len(&self) -> usize939e7bbfa1SBenno Lossin pub const fn len(&self) -> usize { 949e7bbfa1SBenno Lossin self.len 959e7bbfa1SBenno Lossin } 969e7bbfa1SBenno Lossin 979e7bbfa1SBenno Lossin /// Returns `true` when no array elements are represented by this layout. is_empty(&self) -> bool989e7bbfa1SBenno Lossin pub const fn is_empty(&self) -> bool { 999e7bbfa1SBenno Lossin self.len == 0 1009e7bbfa1SBenno Lossin } 1019e7bbfa1SBenno Lossin } 1029e7bbfa1SBenno Lossin 1039e7bbfa1SBenno Lossin impl<T> From<ArrayLayout<T>> for Layout { from(value: ArrayLayout<T>) -> Self1049e7bbfa1SBenno Lossin fn from(value: ArrayLayout<T>) -> Self { 1059e7bbfa1SBenno Lossin let res = Layout::array::<T>(value.len); 1069e7bbfa1SBenno Lossin // SAFETY: By the type invariant of `ArrayLayout` we have 1079e7bbfa1SBenno Lossin // `len * size_of::<T>() <= isize::MAX` and thus the result must be `Ok`. 1089e7bbfa1SBenno Lossin unsafe { res.unwrap_unchecked() } 1099e7bbfa1SBenno Lossin } 1109e7bbfa1SBenno Lossin } 111