use std::cmp::Ordering;
use crate::bus::{BusAddress, Error, MmioAddress, PioAddress};
#[derive(Copy, Clone, Debug)]
pub struct BusRange<A: BusAddress> {
base: A,
size: A::V,
}
impl<A: BusAddress> BusRange<A> {
pub fn new(base: A, size: A::V) -> Result<Self, Error> {
if size == 0.into() {
return Err(Error::InvalidRange);
}
base.checked_add(size - 1.into())
.ok_or(Error::InvalidRange)?;
Ok(BusRange { base, size })
}
pub fn unit(base: A) -> Self {
BusRange {
base,
size: 1.into(),
}
}
pub fn base(&self) -> A {
self.base
}
pub fn size(&self) -> A::V {
self.size
}
pub fn last(&self) -> A {
self.base + (self.size - 1.into())
}
pub fn overlaps(&self, other: &BusRange<A>) -> bool {
!(self.base > other.last() || self.last() < other.base)
}
}
impl<A: BusAddress> PartialEq for BusRange<A> {
fn eq(&self, other: &BusRange<A>) -> bool {
self.base == other.base
}
}
impl<A: BusAddress> Eq for BusRange<A> {}
impl<A: BusAddress> PartialOrd for BusRange<A> {
fn partial_cmp(&self, other: &BusRange<A>) -> Option<Ordering> {
self.base.partial_cmp(&other.base)
}
}
impl<A: BusAddress> Ord for BusRange<A> {
fn cmp(&self, other: &BusRange<A>) -> Ordering {
self.base.cmp(&other.base)
}
}
pub type MmioRange = BusRange<MmioAddress>;
pub type PioRange = BusRange<PioAddress>;
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_bus_range() {
let base_zero = MmioAddress(0);
let value = 5;
assert_eq!(BusRange::new(base_zero, 0), Err(Error::InvalidRange));
assert!(BusRange::new(base_zero, std::u64::MAX).is_ok());
assert!(BusRange::new(MmioAddress(1), std::u64::MAX).is_ok());
assert_eq!(
BusRange::new(MmioAddress(2), std::u64::MAX),
Err(Error::InvalidRange)
);
{
let range = BusRange::new(base_zero, value).unwrap();
assert_eq!(range.base(), base_zero);
assert_eq!(range.size(), value);
assert_eq!(range.last(), MmioAddress(value - 1));
assert!(range.base() < range.last());
}
{
let range = BusRange::unit(base_zero);
assert_eq!(range.base(), base_zero);
assert_eq!(range.last(), range.base());
}
{
let range = BusRange::new(MmioAddress(10), 10).unwrap();
let overlaps = |base_value, len_value| {
range.overlaps(&BusRange::new(MmioAddress(base_value), len_value).unwrap())
};
assert!(!overlaps(0, 5));
assert!(!overlaps(0, 10));
assert!(!overlaps(5, 5));
assert!(overlaps(0, 11));
assert!(overlaps(5, 6));
assert!(overlaps(5, 10));
assert!(overlaps(11, 15));
assert!(overlaps(5, 35));
assert!(overlaps(19, 1));
assert!(overlaps(19, 10));
assert!(!overlaps(20, 1));
assert!(!overlaps(30, 10));
}
{
let base = MmioAddress(10);
let len = 10;
let range = BusRange::new(base, len).unwrap();
assert_eq!(range.cmp(&range), range.partial_cmp(&range).unwrap());
assert_eq!(range.cmp(&range), Ordering::Equal);
{
let other = BusRange::new(base, len + 1).unwrap();
assert_eq!(range, other);
assert_eq!(range.cmp(&other), range.partial_cmp(&other).unwrap());
assert_eq!(range.cmp(&other), Ordering::Equal);
}
{
let other = BusRange::unit(base.checked_add(1).unwrap());
assert_ne!(range, other);
assert_eq!(range.cmp(&other), range.partial_cmp(&other).unwrap());
assert_eq!(range.cmp(&other), Ordering::Less);
}
}
}
}