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::{ArrayLayout, LayoutError}; 54 /// let layout = ArrayLayout::<i32>::new(15)?; 55 /// assert_eq!(layout.len(), 15); 56 /// 57 /// // Errors because `len * size_of::<T>()` overflows. 58 /// let layout = ArrayLayout::<i32>::new(isize::MAX as usize); 59 /// assert!(layout.is_err()); 60 /// 61 /// // Errors because `len * size_of::<i32>() > isize::MAX`, 62 /// // even though `len < isize::MAX`. 63 /// let layout = ArrayLayout::<i32>::new(isize::MAX as usize / 2); 64 /// assert!(layout.is_err()); 65 /// 66 /// # Ok::<(), Error>(()) 67 /// ``` 68 pub const fn new(len: usize) -> Result<Self, LayoutError> { 69 match len.checked_mul(core::mem::size_of::<T>()) { 70 Some(size) if size <= ISIZE_MAX => { 71 // INVARIANT: We checked above that `len * size_of::<T>() <= isize::MAX`. 72 Ok(Self { 73 len, 74 _phantom: PhantomData, 75 }) 76 } 77 _ => Err(LayoutError), 78 } 79 } 80 81 /// Creates a new layout for `[T; len]`. 82 /// 83 /// # Safety 84 /// 85 /// `len` must be a value, for which `len * size_of::<T>() <= isize::MAX` is true. 86 pub const unsafe fn new_unchecked(len: usize) -> Self { 87 // INVARIANT: By the safety requirements of this function 88 // `len * size_of::<T>() <= isize::MAX`. 89 Self { 90 len, 91 _phantom: PhantomData, 92 } 93 } 94 95 /// Returns the number of array elements represented by this layout. 96 pub const fn len(&self) -> usize { 97 self.len 98 } 99 100 /// Returns `true` when no array elements are represented by this layout. 101 pub const fn is_empty(&self) -> bool { 102 self.len == 0 103 } 104 105 /// Returns the size of the [`ArrayLayout`] in bytes. 106 pub const fn size(&self) -> usize { 107 self.len() * core::mem::size_of::<T>() 108 } 109 } 110 111 impl<T> From<ArrayLayout<T>> for Layout { 112 fn from(value: ArrayLayout<T>) -> Self { 113 let res = Layout::array::<T>(value.len); 114 // SAFETY: By the type invariant of `ArrayLayout` we have 115 // `len * size_of::<T>() <= isize::MAX` and thus the result must be `Ok`. 116 unsafe { res.unwrap_unchecked() } 117 } 118 } 119