memory_addr/
iter.rs

1use crate::MemoryAddr;
2
3/// A page-by-page iterator.
4///
5/// The page size is specified by the generic parameter `PAGE_SIZE`, which must
6/// be a power of 2.
7///
8/// The address type is specified by the type parameter `A`.
9///
10/// # Examples
11///
12/// ```
13/// use memory_addr::PageIter;
14///
15/// let mut iter = PageIter::<0x1000, usize>::new(0x1000, 0x3000).unwrap();
16/// assert_eq!(iter.next(), Some(0x1000));
17/// assert_eq!(iter.next(), Some(0x2000));
18/// assert_eq!(iter.next(), None);
19///
20/// assert!(PageIter::<0x1000, usize>::new(0x1000, 0x3001).is_none());
21/// ```
22pub struct PageIter<const PAGE_SIZE: usize, A>
23where
24    A: MemoryAddr,
25{
26    start: A,
27    end: A,
28}
29
30impl<A, const PAGE_SIZE: usize> PageIter<PAGE_SIZE, A>
31where
32    A: MemoryAddr,
33{
34    /// Creates a new [`PageIter`].
35    ///
36    /// Returns `None` if `PAGE_SIZE` is not a power of 2, or `start` or `end`
37    /// is not page-aligned.
38    pub fn new(start: A, end: A) -> Option<Self> {
39        if !PAGE_SIZE.is_power_of_two()
40            || !start.is_aligned(PAGE_SIZE)
41            || !end.is_aligned(PAGE_SIZE)
42        {
43            None
44        } else {
45            Some(Self { start, end })
46        }
47    }
48}
49
50impl<A, const PAGE_SIZE: usize> Iterator for PageIter<PAGE_SIZE, A>
51where
52    A: MemoryAddr,
53{
54    type Item = A;
55
56    fn next(&mut self) -> Option<Self::Item> {
57        if self.start < self.end {
58            let ret = self.start;
59            self.start = self.start.add(PAGE_SIZE);
60            Some(ret)
61        } else {
62            None
63        }
64    }
65}
66
67/// A page-by-page iterator with dynamic page size.
68///
69/// The address type is specified by the type parameter `A`.
70///
71/// # Examples
72///
73/// ```
74/// use memory_addr::DynPageIter;
75///
76/// let mut iter = DynPageIter::<usize>::new(0x1000, 0x3000, 0x1000).unwrap();
77/// assert_eq!(iter.next(), Some(0x1000));
78/// assert_eq!(iter.next(), Some(0x2000));
79/// assert_eq!(iter.next(), None);
80///
81/// assert!(DynPageIter::<usize>::new(0x1000, 0x3001, 0x1000).is_none());
82/// assert!(DynPageIter::<usize>::new(0x1000, 0x3000, 0x1001).is_none());
83/// ```
84pub struct DynPageIter<A>
85where
86    A: MemoryAddr,
87{
88    start: A,
89    end: A,
90    page_size: usize,
91}
92
93impl<A> DynPageIter<A>
94where
95    A: MemoryAddr,
96{
97    /// Creates a new [`DynPageIter`].
98    ///
99    /// Returns `None` if `page_size` is not a power of 2, or `start` or `end`
100    /// is not page-aligned.
101    pub fn new(start: A, end: A, page_size: usize) -> Option<Self> {
102        if !page_size.is_power_of_two()
103            || !start.is_aligned(page_size)
104            || !end.is_aligned(page_size)
105        {
106            None
107        } else {
108            Some(Self {
109                start,
110                end,
111                page_size,
112            })
113        }
114    }
115}
116
117impl<A> Iterator for DynPageIter<A>
118where
119    A: MemoryAddr,
120{
121    type Item = A;
122
123    fn next(&mut self) -> Option<Self::Item> {
124        if self.start < self.end {
125            let ret = self.start;
126            self.start = self.start.add(self.page_size);
127            Some(ret)
128        } else {
129            None
130        }
131    }
132}