xref: /linux/rust/kernel/alloc/layout.rs (revision f2ad904e923f70a80f478febf001f88dfd65a64c)
1 // SPDX-License-Identifier: GPL-2.0
2 
3 //! Memory layout.
4 //!
5 //! Custom layout types extending or improving [`Layout`].
6 
7 use core::{alloc::Layout, marker::PhantomData};
8 
9 /// Error when constructing an [`ArrayLayout`].
10 pub struct LayoutError;
11 
12 /// A layout for an array `[T; n]`.
13 ///
14 /// # Invariants
15 ///
16 /// - `len * size_of::<T>() <= isize::MAX`.
17 pub struct ArrayLayout<T> {
18     len: usize,
19     _phantom: PhantomData<fn() -> T>,
20 }
21 
22 impl<T> Clone for ArrayLayout<T> {
23     fn clone(&self) -> Self {
24         *self
25     }
26 }
27 impl<T> Copy for ArrayLayout<T> {}
28 
29 const ISIZE_MAX: usize = isize::MAX as usize;
30 
31 impl<T> ArrayLayout<T> {
32     /// Creates a new layout for `[T; 0]`.
33     pub const fn empty() -> Self {
34         // INVARIANT: `0 * size_of::<T>() <= isize::MAX`.
35         Self {
36             len: 0,
37             _phantom: PhantomData,
38         }
39     }
40 
41     /// Creates a new layout for `[T; len]`.
42     ///
43     /// # Errors
44     ///
45     /// When `len * size_of::<T>()` overflows or when `len * size_of::<T>() > isize::MAX`.
46     ///
47     /// # Examples
48     ///
49     /// ```
50     /// # use kernel::alloc::layout::{ArrayLayout, LayoutError};
51     /// let layout = ArrayLayout::<i32>::new(15)?;
52     /// assert_eq!(layout.len(), 15);
53     ///
54     /// // Errors because `len * size_of::<T>()` overflows.
55     /// let layout = ArrayLayout::<i32>::new(isize::MAX as usize);
56     /// assert!(layout.is_err());
57     ///
58     /// // Errors because `len * size_of::<i32>() > isize::MAX`,
59     /// // even though `len < isize::MAX`.
60     /// let layout = ArrayLayout::<i32>::new(isize::MAX as usize / 2);
61     /// assert!(layout.is_err());
62     ///
63     /// # Ok::<(), Error>(())
64     /// ```
65     pub const fn new(len: usize) -> Result<Self, LayoutError> {
66         match len.checked_mul(core::mem::size_of::<T>()) {
67             Some(size) if size <= ISIZE_MAX => {
68                 // INVARIANT: We checked above that `len * size_of::<T>() <= isize::MAX`.
69                 Ok(Self {
70                     len,
71                     _phantom: PhantomData,
72                 })
73             }
74             _ => Err(LayoutError),
75         }
76     }
77 
78     /// Creates a new layout for `[T; len]`.
79     ///
80     /// # Safety
81     ///
82     /// `len` must be a value, for which `len * size_of::<T>() <= isize::MAX` is true.
83     pub unsafe fn new_unchecked(len: usize) -> Self {
84         // INVARIANT: By the safety requirements of this function
85         // `len * size_of::<T>() <= isize::MAX`.
86         Self {
87             len,
88             _phantom: PhantomData,
89         }
90     }
91 
92     /// Returns the number of array elements represented by this layout.
93     pub const fn len(&self) -> usize {
94         self.len
95     }
96 
97     /// Returns `true` when no array elements are represented by this layout.
98     pub const fn is_empty(&self) -> bool {
99         self.len == 0
100     }
101 }
102 
103 impl<T> From<ArrayLayout<T>> for Layout {
104     fn from(value: ArrayLayout<T>) -> Self {
105         let res = Layout::array::<T>(value.len);
106         // SAFETY: By the type invariant of `ArrayLayout` we have
107         // `len * size_of::<T>() <= isize::MAX` and thus the result must be `Ok`.
108         unsafe { res.unwrap_unchecked() }
109     }
110 }
111