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