free_list/
page_layout.rs

1use core::alloc::Layout;
2use core::fmt;
3
4use align_address::usize_is_aligned_to;
5
6use crate::PAGE_SIZE;
7
8/// Invalid parameters used in [`PageLayout`] construction.
9#[non_exhaustive]
10#[derive(Clone, PartialEq, Eq, Debug)]
11pub struct PageLayoutError;
12
13impl fmt::Display for PageLayoutError {
14    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
15        f.write_str("invalid parameters to PageLayout::from_size_align")
16    }
17}
18
19/// Layout of a range of pages.
20///
21/// This is analogous to [`Layout`], but requires the size and alignment to refer to whole pages.
22#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
23pub struct PageLayout(Layout);
24
25impl PageLayout {
26    /// Constructs a `PageLayout` from a given `size` and `align`,
27    /// or returns `PageLayoutError` if any of the following conditions
28    /// are not met:
29    ///
30    /// * `align` must not be zero,
31    ///
32    /// * `align` must be a power of two,
33    ///
34    /// * `size`, when rounded up to the nearest multiple of `align`,
35    ///    must not overflow isize (i.e., the rounded value must be
36    ///    less than or equal to `isize::MAX`),
37    ///
38    /// * `size` and `align` must both be aligned to [`PAGE_SIZE`].
39    #[inline]
40    pub const fn from_size_align(size: usize, align: usize) -> Result<Self, PageLayoutError> {
41        if !usize_is_aligned_to(size, PAGE_SIZE) {
42            return Err(PageLayoutError);
43        }
44
45        if !usize_is_aligned_to(align, PAGE_SIZE) {
46            return Err(PageLayoutError);
47        }
48
49        match Layout::from_size_align(size, align) {
50            Ok(layout) => Ok(Self(layout)),
51            Err(_) => Err(PageLayoutError),
52        }
53    }
54
55    /// Creates a page layout, bypassing all checks.
56    ///
57    /// # Safety
58    ///
59    /// This function is unsafe as it does not verify the preconditions from [`PageLayout::from_size_align`].
60    #[must_use]
61    #[inline]
62    pub const unsafe fn from_size_align_unchecked(size: usize, align: usize) -> Self {
63        // SAFETY: the caller is required to uphold the preconditions.
64        unsafe { Self(Layout::from_size_align_unchecked(size, align)) }
65    }
66
67    /// Creates a page layout with [`PAGE_SIZE`] alignment.
68    #[inline]
69    pub const fn from_size(size: usize) -> Result<Self, PageLayoutError> {
70        Self::from_size_align(size, PAGE_SIZE)
71    }
72
73    /// The minimum size in bytes for a memory block of this page layout.
74    #[must_use]
75    #[inline]
76    pub const fn size(&self) -> usize {
77        self.0.size()
78    }
79
80    /// The minimum byte
81    #[must_use]
82    #[inline]
83    pub const fn align(&self) -> usize {
84        self.0.align()
85    }
86}
87
88impl TryFrom<Layout> for PageLayout {
89    type Error = PageLayoutError;
90
91    #[inline]
92    fn try_from(value: Layout) -> Result<Self, Self::Error> {
93        Self::from_size_align(value.size(), value.align())
94    }
95}
96
97impl From<PageLayout> for Layout {
98    #[inline]
99    fn from(value: PageLayout) -> Self {
100        value.0
101    }
102}