File Index
Files and directories
Sign in
FILE

layout.rs

File preview with syntax highlighting.

linux-6.19.14/rust/kernel/alloc/layout.rs RUST
  1// SPDX-License-Identifier: GPL-2.0
  2
  3//! Memory layout.
  4//!
  5//! Custom layout types extending or improving [`Layout`].
  6
  7use core::{alloc::Layout, marker::PhantomData};
  8
  9/// Error when constructing an [`ArrayLayout`].
 10pub struct LayoutError;
 11
 12/// A layout for an array `[T; n]`.
 13///
 14/// # Invariants
 15///
 16/// - `len * size_of::<T>() <= isize::MAX`.
 17pub struct ArrayLayout<T> {
 18    len: usize,
 19    _phantom: PhantomData<fn() -> T>,
 20}
 21
 22impl<T> Clone for ArrayLayout<T> {
 23    fn clone(&self) -> Self {
 24        *self
 25    }
 26}
 27impl<T> Copy for ArrayLayout<T> {}
 28
 29const ISIZE_MAX: usize = isize::MAX as usize;
 30
 31impl<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 const 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    /// Returns the size of the [`ArrayLayout`] in bytes.
103    pub const fn size(&self) -> usize {
104        self.len() * core::mem::size_of::<T>()
105    }
106}
107
108impl<T> From<ArrayLayout<T>> for Layout {
109    fn from(value: ArrayLayout<T>) -> Self {
110        let res = Layout::array::<T>(value.len);
111        // SAFETY: By the type invariant of `ArrayLayout` we have
112        // `len * size_of::<T>() <= isize::MAX` and thus the result must be `Ok`.
113        unsafe { res.unwrap_unchecked() }
114    }
115}
~/ Read-only file preview.