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