diff --git a/src/interval_set.rs b/src/interval_set.rs index acc6a74..111c3b1 100644 --- a/src/interval_set.rs +++ b/src/interval_set.rs @@ -1,5 +1,4 @@ use super::*; -use std::convert::From; use std::ops::{Add, BitAnd, BitOr, Deref, DerefMut, Not, Sub}; /// A coalescing set of intervals @@ -159,43 +158,41 @@ impl From<&[Interval]> for IntervalSet { } } -impl Not for &IntervalSet { - type Output = IntervalSet; - fn not(self) -> Self::Output { - self.complement() - } -} -impl Add for &IntervalSet { - type Output = IntervalSet; - fn add(self, other: &IntervalSet) -> Self::Output { - self.union(other) - } -} -impl Sub for &IntervalSet { - type Output = IntervalSet; - fn sub(self, other: &IntervalSet) -> Self::Output { - self.difference(other) - } -} -impl BitOr for &IntervalSet { - type Output = IntervalSet; - fn bitor(self, other: &IntervalSet) -> Self::Output { - self.union(other) - } -} -impl BitAnd for &IntervalSet { - type Output = IntervalSet; - fn bitand(self, other: &IntervalSet) -> Self::Output { - self.intersection(other) - } -} impl Not for IntervalSet { - type Output = IntervalSet; - fn not(self) -> Self::Output { + type Output = Self; + fn not(self) -> Self { self.complement() } } +impl Add for IntervalSet { + type Output = Self; + fn add(self, other: Self) -> Self { + self.union(&other) + } +} + +impl Sub for IntervalSet { + type Output = Self; + fn sub(self, other: Self) -> Self::Output { + self.difference(&other) + } +} + +impl BitOr for IntervalSet { + type Output = Self; + fn bitor(self, other: Self) -> Self { + self.union(&other) + } +} + +impl BitAnd for IntervalSet { + type Output = Self; + fn bitand(self, other: Self) -> Self { + self.intersection(&other) + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/src/resource_interval.rs b/src/resource_interval.rs index ab36f15..38b82e9 100644 --- a/src/resource_interval.rs +++ b/src/resource_interval.rs @@ -5,12 +5,29 @@ use std::ops::{Add, Deref, DerefMut, Sub}; /// represent where a resource is available, or where it's required /// Resources are independent, so overlaps between the /// interval sets are possible. +#[derive(Debug, PartialEq)] pub struct ResourceInterval(HashMap); impl ResourceInterval { - fn new() -> Self { + pub fn new() -> Self { ResourceInterval(HashMap::new()) } + + pub fn insert(&mut self, other: ResourceInterval) { + for (res, is) in other.iter() { + self.0 + .entry(res.clone()) + .or_insert(IntervalSet::new()) + .merge(is); + } + } + + pub fn remove(&mut self, other: ResourceInterval) { + for (res, is) in other.iter() { + let avail = self.0.entry(res.clone()).or_insert(IntervalSet::new()); + *avail = avail.difference(is); + } + } } impl Deref for ResourceInterval { @@ -37,9 +54,9 @@ impl From<&HashMap> for ResourceInterval { } } -impl Add for &ResourceInterval { +impl Add for ResourceInterval { type Output = ResourceInterval; - fn add(self, other: &ResourceInterval) -> Self::Output { + fn add(self, other: ResourceInterval) -> Self::Output { let res: HashMap = other.0.iter().fold(self.0.clone(), |mut acc, (res, is)| { acc.entry(res.clone()) @@ -51,16 +68,62 @@ impl Add for &ResourceInterval { } } -impl Sub for &ResourceInterval { +impl Sub for ResourceInterval { type Output = ResourceInterval; - fn sub(self, other: &ResourceInterval) -> Self::Output { - let res: HashMap = - other.0.iter().fold(self.0.clone(), |mut acc, (res, is)| { - acc.entry(res.clone()) - .or_insert(IntervalSet::new()) - .difference(is); - acc - }); + fn sub(self, other: ResourceInterval) -> Self::Output { + let res: HashMap = self + .0 + .iter() + .map(|(res, is)| { + ( + res.clone(), + is.difference(other.get(res).unwrap_or(&IntervalSet::new())), + ) + }) + .collect(); ResourceInterval(res) } } + +#[cfg(test)] +mod tests { + use super::*; + + macro_rules! intv { + ( $x:literal, $y:literal ) => { + Interval::new( + Utc.ymd(2022, 1, 1).and_hms($x, 0, 0), + Utc.ymd(2022, 1, 1).and_hms($y, 0, 0), + ) + }; + } + + macro_rules! ri { + ( $r:literal, $(($x:literal, $y:literal)),* ) => { + ResourceInterval::from(HashMap::from([( + $r.to_owned(), + IntervalSet::from(vec![$(intv!($x, $y)),*]), + )])) + }; + } + + #[test] + fn test_conversion() { + let ri = ResourceInterval::from(HashMap::from([("alpha".to_owned(), IntervalSet::new())])); + assert_eq!(ri.len(), 1); + } + + #[test] + fn test_addition() { + let a = ri!("alpha", (13, 15)); + + assert_eq!(a + ri!("alpha", (15, 18)), ri!("alpha", (13, 18))); + } + + #[test] + fn test_subtraction() { + let a = ri!("alpha", (13, 18)); + + assert_eq!(a - ri!("alpha", (15, 16)), ri!("alpha", (13, 15), (16, 18))); + } +} diff --git a/src/task.rs b/src/task.rs index 1283342..e51200f 100644 --- a/src/task.rs +++ b/src/task.rs @@ -157,7 +157,7 @@ impl Task { )])); self.provides.iter().all(|res| { if let Some(is) = available.get(res) { - !(&horizon_is - is).is_empty() + !(horizon_is.difference(is)).is_empty() } else { false }