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}