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