Skip to main content

frame_alloc/
page_size.rs

1use core::num::{NonZeroU8, NonZeroUsize};
2
3/// A power-of-two page size, stored as a bit-shift (log2 of bytes).
4///
5/// # Safety invariant
6/// The inner value must be a valid page size for the target architecture.
7#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
8pub struct PageSize(NonZeroU8);
9
10impl PageSize {
11    /// Construct a PageSize from a log2 value. Panics if shift is 0 or >= usize::BITS.
12    pub const fn from_log2(shift: u8) -> Self {
13        assert!(shift > 0 && (shift as u32) < usize::BITS);
14        // SAFETY: shift > 0 asserted above
15        Self(unsafe { NonZeroU8::new_unchecked(shift) })
16    }
17
18    /// The size in bytes.
19    pub const fn bytes(&self) -> usize {
20        1usize << self.0.get()
21    }
22
23    /// The log2 / bit-shift value.
24    #[inline]
25    pub const fn log2(self) -> u8 {
26        self.0.get()
27    }
28
29    /// Total bytes for `count` frames of this size.
30    /// Returns `None` on overflow.
31    #[inline]
32    pub const fn total_bytes(self, count: NonZeroUsize) -> Option<usize> {
33        self.bytes().checked_mul(count.get())
34    }
35
36    /// True if `addr` is naturally aligned to this page size.
37    #[inline]
38    pub const fn is_aligned(self, addr: usize) -> bool {
39        addr & (self.bytes() - 1) == 0
40    }
41
42    /// Round `addr` down to the nearest aligned frame base.
43    #[inline]
44    pub const fn align_down(self, addr: usize) -> usize {
45        addr & !(self.bytes() - 1)
46    }
47
48    /// Round `addr` up to the next aligned frame base.
49    /// Returns `None` on overflow.
50    #[inline]
51    pub const fn align_up(self, addr: usize) -> Option<usize> {
52        let mask = self.bytes() - 1;
53        match addr.checked_add(mask) {
54            Some(a) => Some(a & !mask),
55            None => None,
56        }
57    }
58}