kernel/alloc/layout.rs
1// SPDX-License-Identifier: GPL-2.0
2
3//! Memory layout.
4//!
5//! Custom layout types extending or improving [`Layout`].
6
7use core::{
8 alloc::Layout,
9 marker::PhantomData, //
10};
11
12/// Error when constructing an [`ArrayLayout`].
13pub struct LayoutError;
14
15/// A layout for an array `[T; n]`.
16///
17/// # Invariants
18///
19/// - `len * size_of::<T>() <= isize::MAX`.
20pub struct ArrayLayout<T> {
21 len: usize,
22 _phantom: PhantomData<fn() -> T>,
23}
24
25impl<T> Clone for ArrayLayout<T> {
26 fn clone(&self) -> Self {
27 *self
28 }
29}
30impl<T> Copy for ArrayLayout<T> {}
31
32const ISIZE_MAX: usize = isize::MAX as usize;
33
34impl<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
114impl<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}