use std::ops::RangeInclusive;
use crate::AddressType;
#[derive(PartialEq, Eq)]
#[derive(Debug)]
pub struct MemoryRegion<D: Clone> {
lower_bound: AddressType,
upper_bound: AddressType,
description: D,
}
impl<D: Clone> MemoryRegion<D> {
pub(crate) fn new(lower_bound: AddressType, upper_bound: AddressType, description: D) -> Result<Self, String> {
if lower_bound >= upper_bound {
return Err(format!("lower bound ({}) is bigger than or equal to upper bound ({})", lower_bound, upper_bound));
}
Ok(Self {
lower_bound,
upper_bound,
description,
})
}
pub fn address_in_region(&self, address: AddressType) -> bool {
self.lower_bound <= address && address <= self.upper_bound
}
pub fn address_comes_after(&self, address: AddressType) -> bool {
self.upper_bound < address
}
pub fn overlaps(&self, other: &MemoryRegion<D>) -> bool {
self.upper_bound >= other.lower_bound && self.lower_bound <= other.upper_bound
}
pub fn comes_after(&self, other: &MemoryRegion<D>) -> bool {
self.lower_bound > other.upper_bound
}
pub fn starts_at_zero(&self) -> bool {
self.lower_bound == 0
}
pub fn is_adjacent_to(&self, other: &MemoryRegion<D>) -> bool {
self.upper_bound.wrapping_add(1) == other.lower_bound || self.lower_bound == other.upper_bound.wrapping_add(1)
}
pub(crate) fn region_between_zero_and_self(&self, description: &D) -> Result<Option<MemoryRegion<D>>, String> {
Ok(
if self.starts_at_zero() {
None
} else {
Some(Self::new(0, self.lower_bound.wrapping_sub(1), description.clone())?)
}
)
}
pub(crate) fn region_between(&self, other: &MemoryRegion<D>, description: &D) -> Result<Option<MemoryRegion<D>>, String> {
Ok(
if self.is_adjacent_to(other) {
None
} else {
Some(Self::new(self.upper_bound, other.lower_bound.wrapping_sub(1), description.clone())?)
}
)
}
pub fn lower_bound(&self) -> AddressType {
self.lower_bound
}
pub fn upper_bound(&self) -> AddressType {
self.upper_bound
}
pub fn description(&self) -> D {
self.description.clone()
}
pub fn to_range(&self) -> RangeInclusive<AddressType> {
self.lower_bound..=self.upper_bound
}
}
#[cfg(test)]
mod tests {
use super::*;
const MR_1: MemoryRegion<&str> = MemoryRegion { lower_bound: 0, upper_bound: 255, description: "test" };
const MR_2: MemoryRegion<&str> = MemoryRegion { lower_bound: 16, upper_bound: 31, description: "test" };
const MR_3: MemoryRegion<&str> = MemoryRegion { lower_bound: 16, upper_bound: 32, description: "test" };
const MR_4: MemoryRegion<&str> = MemoryRegion { lower_bound: 32, upper_bound: 64, description: "test" };
#[test]
fn memory_region_construction() {
assert_eq!(
MemoryRegion::new(0, 6, "test"),
Ok(MemoryRegion {
lower_bound: 0,
upper_bound: 6,
description: "test"
})
);
assert!(MemoryRegion::new(6, 0, "test").is_err());
}
#[test]
fn memory_region_overlap() {
assert!(MR_1.overlaps(&MR_2));
assert!(MR_1.overlaps(&MR_4));
assert!(!MR_2.overlaps(&MR_4));
assert!(MR_3.overlaps(&MR_4));
assert!(MR_2.overlaps(&MR_1));
assert!(MR_4.overlaps(&MR_1));
assert!(!MR_4.overlaps(&MR_2));
assert!(MR_4.overlaps(&MR_3));
assert!(MR_1.overlaps(&MR_1));
}
#[test]
fn memory_region_adjacency() {
assert!(!MR_1.is_adjacent_to(&MR_2));
assert!(MR_2.is_adjacent_to(&MR_4));
assert!(!MR_3.is_adjacent_to(&MR_4));
}
}