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