use crate::error::{Error, Result};
use std::ops::Range;
pub fn after(
origin: *const (),
range: Option<Range<usize>>,
) -> impl Iterator<Item = Result<*const ()>> {
FreeRegionIter::new(origin, range, SearchDirection::After)
}
pub fn before(
origin: *const (),
range: Option<Range<usize>>,
) -> impl Iterator<Item = Result<*const ()>> {
FreeRegionIter::new(origin, range, SearchDirection::Before)
}
enum SearchDirection {
Before,
After,
}
struct FreeRegionIter {
range: Range<usize>,
search: SearchDirection,
current: usize,
}
impl FreeRegionIter {
fn new(origin: *const (), range: Option<Range<usize>>, search: SearchDirection) -> Self {
FreeRegionIter {
range: range.unwrap_or(0..usize::max_value()),
current: origin as usize,
search,
}
}
}
impl Iterator for FreeRegionIter {
type Item = Result<*const ()>;
fn next(&mut self) -> Option<Self::Item> {
let page_size = region::page::size();
while self.current > 0 && self.range.contains(&self.current) {
match region::query(self.current as *const usize) {
Ok(region) => {
let range = region.as_range();
self.current = match self.search {
SearchDirection::Before => range.start.saturating_sub(page_size),
SearchDirection::After => range.end,
}
},
Err(error) => {
let result = Some(match error {
region::Error::UnmappedRegion => Ok(self.current as *const _),
inner => Err(Error::RegionFailure(inner)),
});
self.current = match self.search {
SearchDirection::Before => self.current.saturating_sub(page_size),
SearchDirection::After => self.current + page_size,
};
return result;
},
}
}
None
}
}