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 pub const fn new(len: usize) -> Result<Self, LayoutError> { 47 match len.checked_mul(core::mem::size_of::<T>()) { 48 Some(size) if size <= ISIZE_MAX => { 49 // INVARIANT: We checked above that `len * size_of::<T>() <= isize::MAX`. 50 Ok(Self { 51 len, 52 _phantom: PhantomData, 53 }) 54 } 55 _ => Err(LayoutError), 56 } 57 } 58 59 /// Creates a new layout for `[T; len]`. 60 /// 61 /// # Safety 62 /// 63 /// `len` must be a value, for which `len * size_of::<T>() <= isize::MAX` is true. 64 pub unsafe fn new_unchecked(len: usize) -> Self { 65 // INVARIANT: By the safety requirements of this function 66 // `len * size_of::<T>() <= isize::MAX`. 67 Self { 68 len, 69 _phantom: PhantomData, 70 } 71 } 72 73 /// Returns the number of array elements represented by this layout. 74 pub const fn len(&self) -> usize { 75 self.len 76 } 77 78 /// Returns `true` when no array elements are represented by this layout. 79 pub const fn is_empty(&self) -> bool { 80 self.len == 0 81 } 82 } 83 84 impl<T> From<ArrayLayout<T>> for Layout { 85 fn from(value: ArrayLayout<T>) -> Self { 86 let res = Layout::array::<T>(value.len); 87 // SAFETY: By the type invariant of `ArrayLayout` we have 88 // `len * size_of::<T>() <= isize::MAX` and thus the result must be `Ok`. 89 unsafe { res.unwrap_unchecked() } 90 } 91 } 92