layout.rs 2.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. // SPDX-License-Identifier: GPL-2.0
  2. //! Memory layout.
  3. //!
  4. //! Custom layout types extending or improving [`Layout`].
  5. use core::{alloc::Layout, marker::PhantomData};
  6. /// Error when constructing an [`ArrayLayout`].
  7. pub struct LayoutError;
  8. /// A layout for an array `[T; n]`.
  9. ///
  10. /// # Invariants
  11. ///
  12. /// - `len * size_of::<T>() <= isize::MAX`.
  13. pub struct ArrayLayout<T> {
  14. len: usize,
  15. _phantom: PhantomData<fn() -> T>,
  16. }
  17. impl<T> Clone for ArrayLayout<T> {
  18. fn clone(&self) -> Self {
  19. *self
  20. }
  21. }
  22. impl<T> Copy for ArrayLayout<T> {}
  23. const ISIZE_MAX: usize = isize::MAX as usize;
  24. impl<T> ArrayLayout<T> {
  25. /// Creates a new layout for `[T; 0]`.
  26. pub const fn empty() -> Self {
  27. // INVARIANT: `0 * size_of::<T>() <= isize::MAX`.
  28. Self {
  29. len: 0,
  30. _phantom: PhantomData,
  31. }
  32. }
  33. /// Creates a new layout for `[T; len]`.
  34. ///
  35. /// # Errors
  36. ///
  37. /// When `len * size_of::<T>()` overflows or when `len * size_of::<T>() > isize::MAX`.
  38. pub const fn new(len: usize) -> Result<Self, LayoutError> {
  39. match len.checked_mul(core::mem::size_of::<T>()) {
  40. Some(size) if size <= ISIZE_MAX => {
  41. // INVARIANT: We checked above that `len * size_of::<T>() <= isize::MAX`.
  42. Ok(Self {
  43. len,
  44. _phantom: PhantomData,
  45. })
  46. }
  47. _ => Err(LayoutError),
  48. }
  49. }
  50. /// Creates a new layout for `[T; len]`.
  51. ///
  52. /// # Safety
  53. ///
  54. /// `len` must be a value, for which `len * size_of::<T>() <= isize::MAX` is true.
  55. pub unsafe fn new_unchecked(len: usize) -> Self {
  56. // INVARIANT: By the safety requirements of this function
  57. // `len * size_of::<T>() <= isize::MAX`.
  58. Self {
  59. len,
  60. _phantom: PhantomData,
  61. }
  62. }
  63. /// Returns the number of array elements represented by this layout.
  64. pub const fn len(&self) -> usize {
  65. self.len
  66. }
  67. /// Returns `true` when no array elements are represented by this layout.
  68. pub const fn is_empty(&self) -> bool {
  69. self.len == 0
  70. }
  71. }
  72. impl<T> From<ArrayLayout<T>> for Layout {
  73. fn from(value: ArrayLayout<T>) -> Self {
  74. let res = Layout::array::<T>(value.len);
  75. // SAFETY: By the type invariant of `ArrayLayout` we have
  76. // `len * size_of::<T>() <= isize::MAX` and thus the result must be `Ok`.
  77. unsafe { res.unwrap_unchecked() }
  78. }
  79. }