xref: /linux-6.15/rust/kernel/alloc/layout.rs (revision 91da5a24)
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