1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
use super::{FrameSize, Size4KiB, VAddr};
use core::{
    iter::Step,
    marker::PhantomData,
    ops::{Add, AddAssign},
};

#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
pub struct Page<S: FrameSize = Size4KiB> {
    pub start: VAddr,
    _phantom: PhantomData<S>,
}

impl<S> Page<S>
where
    S: FrameSize,
{
    pub fn starts_with(address: VAddr) -> Page<S> {
        assert!(usize::from(address) % S::SIZE == 0, "Address is not at the start of a page");
        Page { start: address, _phantom: PhantomData }
    }

    pub fn contains(address: VAddr) -> Page<S> {
        Page { start: address.align_down(S::SIZE), _phantom: PhantomData }
    }
}

impl<S> Add<usize> for Page<S>
where
    S: FrameSize,
{
    type Output = Page<S>;

    fn add(self, num_pages: usize) -> Self::Output {
        Page::contains(self.start + num_pages * S::SIZE)
    }
}

impl<S> AddAssign<usize> for Page<S>
where
    S: FrameSize,
{
    fn add_assign(&mut self, num_pages: usize) {
        *self = *self + num_pages;
    }
}

impl<S> Step for Page<S>
where
    S: FrameSize,
{
    fn steps_between(start: &Self, end: &Self) -> Option<usize> {
        let address_difference = usize::from(end.start).checked_sub(usize::from(start.start))?;
        assert!(address_difference % S::SIZE == 0);
        Some(address_difference / S::SIZE)
    }

    fn forward_checked(start: Self, count: usize) -> Option<Self> {
        Some(Page { start: start.start.checked_add(S::SIZE.checked_mul(count)?)?, _phantom: PhantomData })
    }

    fn backward_checked(start: Self, count: usize) -> Option<Self> {
        Some(Page { start: start.start.checked_sub(S::SIZE.checked_mul(count)?)?, _phantom: PhantomData })
    }
}