Skip to content

Commit

Permalink
Enhanced MemoryAddr (#4)
Browse files Browse the repository at this point in the history
* demo: what if we add more bounds to `MemoryAddr`

* remove arithmetic bounds for `MemoryAddr`, add some provided methods

* rename `MemoryAddr::sub_addr` to `MemoryAddr::offset_from`

* remove a wrong bug todo

* add two more functions to `VirtAddr`

* add `add` and `sub` to `MemoryAddr`

* clarify the behavior of arithmetic operations of `MemoryAddr`, add detailed unit tests

* formatted

* add `overflowing_add/sub` to `MemoryAddr`

* add `checked_add/sub` to `MemoryAddr`

* `AddrRange` candidate B: allow malformed ranges and treat them as empty

* doc and tests improvement for `MemoryAddr` and `AddrRange`

* update `PageIter`

* formatted

* even more tests, ready to merge

* switch to `AddrRange` candidate A
  • Loading branch information
aarkegz authored Aug 26, 2024
1 parent 4e58d27 commit 5f526d6
Show file tree
Hide file tree
Showing 9 changed files with 879 additions and 295 deletions.
595 changes: 506 additions & 89 deletions memory_addr/src/addr.rs

Large diffs are not rendered by default.

16 changes: 9 additions & 7 deletions memory_addr/src/iter.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::is_aligned;
use crate::MemoryAddr;

/// A page-by-page iterator.
///
Expand All @@ -16,27 +16,29 @@ use crate::is_aligned;
/// assert_eq!(iter.next(), Some(0x1000));
/// assert_eq!(iter.next(), Some(0x2000));
/// assert_eq!(iter.next(), None);
///
/// assert!(PageIter::<0x1000, usize>::new(0x1000, 0x3001).is_none());
/// ```
pub struct PageIter<const PAGE_SIZE: usize, A>
where
A: Into<usize> + Copy,
A: MemoryAddr,
{
start: A,
end: A,
}

impl<A, const PAGE_SIZE: usize> PageIter<PAGE_SIZE, A>
where
A: Into<usize> + Copy,
A: MemoryAddr,
{
/// Creates a new [`PageIter`].
///
/// Returns `None` if `PAGE_SIZE` is not a power of 2, or `start` or `end`
/// is not page-aligned.
pub fn new(start: A, end: A) -> Option<Self> {
if !PAGE_SIZE.is_power_of_two()
|| !is_aligned(Into::<usize>::into(start), PAGE_SIZE)
|| !is_aligned(Into::<usize>::into(end), PAGE_SIZE)
|| !start.is_aligned(PAGE_SIZE)
|| !end.is_aligned(PAGE_SIZE)
{
None
} else {
Expand All @@ -47,14 +49,14 @@ where

impl<A, const PAGE_SIZE: usize> Iterator for PageIter<PAGE_SIZE, A>
where
A: Into<usize> + Copy + PartialOrd + core::ops::AddAssign<usize>,
A: MemoryAddr,
{
type Item = A;

fn next(&mut self) -> Option<Self::Item> {
if self.start < self.end {
let ret = self.start;
self.start += PAGE_SIZE;
self.start = self.start.add(PAGE_SIZE);
Some(ret)
} else {
None
Expand Down
78 changes: 13 additions & 65 deletions memory_addr/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,72 +77,20 @@ pub const fn is_aligned_4k(addr: usize) -> bool {

#[cfg(test)]
mod tests {
use crate::{va, va_range, VirtAddrRange};
use super::*;

#[test]
fn test_addr() {
let addr = va!(0x2000);
assert!(addr.is_aligned_4k());
assert!(!addr.is_aligned(0x10000usize));
assert_eq!(addr.align_offset_4k(), 0);
assert_eq!(addr.align_down_4k(), va!(0x2000));
assert_eq!(addr.align_up_4k(), va!(0x2000));

let addr = va!(0x2fff);
assert!(!addr.is_aligned_4k());
assert_eq!(addr.align_offset_4k(), 0xfff);
assert_eq!(addr.align_down_4k(), va!(0x2000));
assert_eq!(addr.align_up_4k(), va!(0x3000));

let align = 0x100000;
let addr = va!(align * 5) + 0x2000;
assert!(addr.is_aligned_4k());
assert!(!addr.is_aligned(align));
assert_eq!(addr.align_offset(align), 0x2000);
assert_eq!(addr.align_down(align), va!(align * 5));
assert_eq!(addr.align_up(align), va!(align * 6));
}

#[test]
fn test_range() {
let start = va!(0x1000);
let end = va!(0x2000);
let range = va_range!(start..end);
println!("range: {:?}", range);

assert!((0x1000..0x1000).is_empty());
assert!((0x1000..0xfff).is_empty());
assert!(!range.is_empty());

assert_eq!(range.start, start);
assert_eq!(range.end, end);
assert_eq!(range.size(), 0x1000);

assert!(range.contains(va!(0x1000)));
assert!(range.contains(va!(0x1080)));
assert!(!range.contains(va!(0x2000)));

assert!(!range.contains_range((0xfff..0x1fff).into()));
assert!(!range.contains_range((0xfff..0x2000).into()));
assert!(!range.contains_range((0xfff..0x2001).into()));
assert!(range.contains_range((0x1000..0x1fff).into()));
assert!(range.contains_range((0x1000..0x2000).into()));
assert!(!range.contains_range((0x1000..0x2001).into()));
assert!(range.contains_range((0x1001..0x1fff).into()));
assert!(range.contains_range((0x1001..0x2000).into()));
assert!(!range.contains_range((0x1001..0x2001).into()));
assert!(!range.contains_range(VirtAddrRange::from_start_size(0xfff.into(), 0x1)));
assert!(!range.contains_range(VirtAddrRange::from_start_size(0x2000.into(), 0x1)));

assert!(range.contained_in((0xfff..0x2000).into()));
assert!(range.contained_in((0x1000..0x2000).into()));
assert!(range.contained_in((0x1000..0x2001).into()));

assert!(!range.overlaps((0x800..0x1000).into()));
assert!(range.overlaps((0x800..0x1001).into()));
assert!(range.overlaps((0x1800..0x2000).into()));
assert!(range.overlaps((0x1800..0x2001).into()));
assert!(!range.overlaps((0x2000..0x2800).into()));
assert!(range.overlaps((0xfff..0x2001).into()));
fn test_align() {
assert_eq!(align_down(0x12345678, 0x1000), 0x12345000);
assert_eq!(align_up(0x12345678, 0x1000), 0x12346000);
assert_eq!(align_offset(0x12345678, 0x1000), 0x678);
assert!(is_aligned(0x12345000, 0x1000));
assert!(!is_aligned(0x12345678, 0x1000));

assert_eq!(align_down_4k(0x12345678), 0x12345000);
assert_eq!(align_up_4k(0x12345678), 0x12346000);
assert_eq!(align_offset_4k(0x12345678), 0x678);
assert!(is_aligned_4k(0x12345000));
assert!(!is_aligned_4k(0x12345678));
}
}
Loading

0 comments on commit 5f526d6

Please sign in to comment.