From ac2d0a724cb3667a52c3d7eec1514a1fcc984134 Mon Sep 17 00:00:00 2001 From: ripytide Date: Wed, 5 Apr 2023 16:05:18 +0100 Subject: [PATCH] added tests back and got them compiling --- src/helpers.rs | 6 +- src/range_bounds_map.rs | 1200 ++++++++++++++++++++++++++++++++++++--- 2 files changed, 1115 insertions(+), 91 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 3efba7f..19fed79 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -41,7 +41,8 @@ where } } -enum Config { +#[derive(Debug, PartialEq)] +pub(crate) enum Config { LeftFirstNonOverlapping, LeftFirstPartialOverlap, LeftContainsRight, @@ -50,7 +51,7 @@ enum Config { RightFirstPartialOverlap, RightContainsLeft, } -fn config(a: A, b: B) -> Config +pub(crate) fn config(a: A, b: B) -> Config where A: NiceRange, B: NiceRange, @@ -121,6 +122,7 @@ where return bound_ord >= start_bound_ord && bound_ord <= end_bound_ord; } +#[derive(Debug)] pub(crate) struct CutResult { pub(crate) before_cut: Option<(Bound, Bound)>, pub(crate) inside_cut: Option<(Bound, Bound)>, diff --git a/src/range_bounds_map.rs b/src/range_bounds_map.rs index 517a5c0..3f5cbe5 100644 --- a/src/range_bounds_map.rs +++ b/src/range_bounds_map.rs @@ -54,9 +54,9 @@ use crate::TryFromBounds; /// /// // Make a map of ranges to booleans /// let mut map = RangeBoundsMap::from_slice_strict([ -/// (4..8, false), -/// (8..18, true), -/// (20..100, false), +/// (ie(4, 8), false), +/// (ie(8, 18), true), +/// (ie(20, 100), false), /// ]) /// .unwrap(); /// @@ -129,6 +129,7 @@ use crate::TryFromBounds; /// /// [`RangeBounds`]: https://doc.rust-lang.org/std/ops/trait.RangeBounds.html /// [`BTreeMap`]: https://doc.rust-lang.org/std/collections/struct.BTreeMap.html +#[derive(Debug, Clone, PartialEq)] pub struct RangeBoundsMap { inner: BTreeMap, phantom: PhantomData, @@ -152,8 +153,8 @@ pub struct OverlapError; /// [`RangeBoundsMap::cut()`]. /// /// In this example we try to cut `4..=6` out of a `RangeBoundsMap` -/// that contains `2..8`. If this was successful then the -/// `RangeBoundsMap` would hold `2..4` and `(Bound::Exclusive(6), +/// that contains `ie(2, 8)`. If this was successful then the +/// `RangeBoundsMap` would hold `ie(2, 4)` and `(Bound::Exclusive(6), /// Bound::Exclusive(8))`. However, since the `RangeBounds` type of /// this `RangeBoundsMap` is `Range<{integer}>` the latter of the two /// new `RangeBounds` is "unrepresentable", and hence will fail to be @@ -164,7 +165,7 @@ pub struct OverlapError; /// use range_bounds_map::{RangeBoundsMap, TryFromBoundsError}; /// /// let mut map = -/// RangeBoundsMap::from_slice_strict([(2..8, true)]).unwrap(); +/// RangeBoundsMap::from_slice_strict([(ie(2, 8), true)]).unwrap(); /// /// assert!(map.cut(&(4..=6)).is_err()); /// ``` @@ -304,7 +305,7 @@ where /// let mut map = RangeBoundsMap::new(); /// /// assert_eq!(map.len(), 0); - /// map.insert_strict(0..1, false).unwrap(); + /// map.insert_strict(ie(0, 1), false).unwrap(); /// assert_eq!(map.len(), 1); /// ``` pub fn len(&self) -> usize { @@ -321,7 +322,7 @@ where /// let mut map = RangeBoundsMap::new(); /// /// assert_eq!(map.is_empty(), true); - /// map.insert_strict(0..1, false).unwrap(); + /// map.insert_strict(ie(0, 1), false).unwrap(); /// assert_eq!(map.is_empty(), false); /// ``` pub fn is_empty(&self) -> bool { @@ -344,13 +345,13 @@ where /// /// let mut map = RangeBoundsMap::new(); /// - /// map.insert_strict(5..10, false); + /// map.insert_strict(ie(5, 10), false); /// /// assert_eq!(map.overlaps(&(1..=3)), false); - /// assert_eq!(map.overlaps(&(4..5)), false); + /// assert_eq!(map.overlaps(ie(4, 5)), false); /// /// assert_eq!(map.overlaps(&(4..=5)), true); - /// assert_eq!(map.overlaps(&(4..6)), true); + /// assert_eq!(map.overlaps(ie(4, 6)), true); /// ``` pub fn overlaps(&self, range: Q) -> bool where @@ -375,17 +376,17 @@ where /// use range_bounds_map::RangeBoundsMap; /// /// let map = RangeBoundsMap::from_slice_strict([ - /// (1..4, false), - /// (4..8, true), - /// (8..100, false), + /// (ie(1, 4), false), + /// (ie(4, 8), true), + /// (ie(8, 100), false), /// ]) /// .unwrap(); /// - /// let mut overlapping = map.overlapping(&(2..8)); + /// let mut overlapping = map.overlapping(ie(2, 8)); /// /// assert_eq!( /// overlapping.collect::>(), - /// [(&(1..4), &false), (&(4..8), &true)] + /// [(ie(1, 4), &false), (ie(4, 8), &true)] /// ); /// ``` pub fn overlapping( @@ -414,9 +415,9 @@ where /// use range_bounds_map::RangeBoundsMap; /// /// let map = RangeBoundsMap::from_slice_strict([ - /// (1..4, false), - /// (4..8, true), - /// (8..100, false), + /// (ie(1, 4), false), + /// (ie(4, 8), true), + /// (ie(8, 100), false), /// ]) /// .unwrap(); /// @@ -436,9 +437,9 @@ where /// use range_bounds_map::RangeBoundsMap; /// /// let map = RangeBoundsMap::from_slice_strict([ - /// (1..4, false), - /// (4..8, true), - /// (8..100, false), + /// (ie(1, 4), false), + /// (ie(4, 8), true), + /// (ie(8, 100), false), /// ]) /// .unwrap(); /// @@ -458,7 +459,7 @@ where /// use range_bounds_map::RangeBoundsMap; /// /// let mut map = - /// RangeBoundsMap::from_slice_strict([(1..4, false)]).unwrap(); + /// RangeBoundsMap::from_slice_strict([(ie(1, 4), false)]).unwrap(); /// /// if let Some(x) = map.get_at_point_mut(&2) { /// *x = true; @@ -479,14 +480,14 @@ where /// use range_bounds_map::RangeBoundsMap; /// /// let map = RangeBoundsMap::from_slice_strict([ - /// (1..4, false), - /// (4..8, true), - /// (8..100, false), + /// (ie(1, 4), false), + /// (ie(4, 8), true), + /// (ie(8, 100), false), /// ]) /// .unwrap(); /// - /// assert_eq!(map.get_entry_at_point(&3), Some((&(1..4), &false))); - /// assert_eq!(map.get_entry_at_point(&4), Some((&(4..8), &true))); + /// assert_eq!(map.get_entry_at_point(&3), Some((ie(1, 4), &false))); + /// assert_eq!(map.get_entry_at_point(&4), Some((ie(4, 8), &true))); /// assert_eq!(map.get_entry_at_point(&101), None); /// ``` pub fn get_entry_at_point(&self, point: I) -> Option<(&K, &V)> { @@ -502,17 +503,17 @@ where /// use range_bounds_map::RangeBoundsMap; /// /// let map = RangeBoundsMap::from_slice_strict([ - /// (1..4, false), - /// (4..8, true), - /// (8..100, false), + /// (ie(1, 4), false), + /// (ie(4, 8), true), + /// (ie(8, 100), false), /// ]) /// .unwrap(); /// /// let mut iter = map.iter(); /// - /// assert_eq!(iter.next(), Some((&(1..4), &false))); - /// assert_eq!(iter.next(), Some((&(4..8), &true))); - /// assert_eq!(iter.next(), Some((&(8..100), &false))); + /// assert_eq!(iter.next(), Some((ie(1, 4), &false))); + /// assert_eq!(iter.next(), Some((ie(4, 8), &true))); + /// assert_eq!(iter.next(), Some((ie(8, 0), &false))); /// assert_eq!(iter.next(), None); /// ``` pub fn iter(&self) -> impl DoubleEndedIterator { @@ -535,20 +536,20 @@ where /// use range_bounds_map::RangeBoundsMap; /// /// let mut map = RangeBoundsMap::from_slice_strict([ - /// (1..4, false), - /// (4..8, true), - /// (8..100, false), + /// (ie(1, 4), false), + /// (ie(4, 8), true), + /// (ie(8, 100), false), /// ]) /// .unwrap(); /// - /// let mut removed = map.remove_overlapping(&(2..8)); + /// let mut removed = map.remove_overlapping(ie(2, 8)); /// /// assert_eq!( /// removed.collect::>(), - /// [(1..4, false), (4..8, true)] + /// [(ie(1, 4), false), (ie(4, 8), true)] /// ); /// - /// assert_eq!(map.iter().collect::>(), [(&(8..100), &false)]); + /// assert_eq!(map.iter().collect::>(), [(ie(8, 0), &false)]); /// ``` pub fn remove_overlapping<'a, Q>( &'a mut self, @@ -593,20 +594,20 @@ where /// use range_bounds_map::{RangeBoundsMap, TryFromBoundsError}; /// /// let mut base = RangeBoundsMap::from_slice_strict([ - /// (1..4, false), - /// (4..8, true), - /// (8..100, false), + /// (ie(1, 4), false), + /// (ie(4, 8), true), + /// (ie(8, 100), false), /// ]) /// .unwrap(); /// /// let after_cut = RangeBoundsMap::from_slice_strict([ - /// (1..2, false), - /// (40..100, false), + /// (ie(1, 2), false), + /// (ie(40, 100), false), /// ]) /// .unwrap(); /// /// assert_eq!( - /// base.cut(&(2..40)).unwrap().collect::>(), + /// base.cut(ie(2, 0)).unwrap().collect::>(), /// [ /// ((Bound::Included(2), Bound::Excluded(4)), false), /// ((Bound::Included(4), Bound::Excluded(8)), true), @@ -780,9 +781,9 @@ where /// use range_bounds_map::RangeBoundsMap; /// /// let map = RangeBoundsMap::from_slice_strict([ - /// (1..3, false), - /// (5..7, true), - /// (9..100, false), + /// (ie(1, 3), false), + /// (ie(5, 7), true), + /// (ie(9, 100), false), /// ]) /// .unwrap(); /// @@ -864,15 +865,15 @@ where /// use range_bounds_map::RangeBoundsMap; /// /// let map = RangeBoundsMap::from_slice_strict([ - /// (1..3, false), - /// (5..8, true), - /// (8..100, false), + /// (ie(1, 3), false), + /// (ie(5, 8), true), + /// (ie(8, 100), false), /// ]) /// .unwrap(); /// - /// assert_eq!(map.contains_range_bounds(&(1..3)), true); - /// assert_eq!(map.contains_range_bounds(&(2..6)), false); - /// assert_eq!(map.contains_range_bounds(&(6..50)), true); + /// assert_eq!(map.contains_range_bounds(ie(1, 3)), true); + /// assert_eq!(map.contains_range_bounds(ie(2, 6)), false); + /// assert_eq!(map.contains_range_bounds(ie(6, 0)), true); /// ``` pub fn contains_range_bounds(&self, range_bounds: Q) -> bool where @@ -902,8 +903,8 @@ where /// /// let mut map = RangeBoundsMap::new(); /// - /// assert_eq!(map.insert_strict(5..10, 9), Ok(())); - /// assert_eq!(map.insert_strict(5..10, 2), Err(OverlapError)); + /// assert_eq!(map.insert_strict(ie(5, 10), 9), Ok(())); + /// assert_eq!(map.insert_strict(ie(5, 10), 2), Err(OverlapError)); /// assert_eq!(map.len(), 1); /// ``` pub fn insert_strict( @@ -997,26 +998,26 @@ where /// }; /// /// let mut map = - /// RangeBoundsMap::from_slice_strict([(1..4, false)]).unwrap(); + /// RangeBoundsMap::from_slice_strict([(ie(1, 4), false)]).unwrap(); /// /// // Touching - /// assert_eq!(map.insert_merge_touching(4..6, true), Ok(&(1..6))); + /// assert_eq!(map.insert_merge_touching(ie(4, 6), true), Ok(ie(1, 6))); /// /// // Overlapping /// assert_eq!( - /// map.insert_merge_touching(4..8, false), + /// map.insert_merge_touching(ie(4, 8), false), /// Err(OverlapOrTryFromBoundsError::Overlap(OverlapError)), /// ); /// /// // Neither Touching or Overlapping /// assert_eq!( - /// map.insert_merge_touching(10..16, false), - /// Ok(&(10..16)) + /// map.insert_merge_touching(ie(10, 16), false), + /// Ok(ie(0, 6)) /// ); /// /// assert_eq!( /// map.iter().collect::>(), - /// [(&(1..6), &true), (&(10..16), &false)] + /// [(ie(1, 6), &true), (ie(0, 6), &false)] /// ); /// ``` pub fn insert_merge_touching( @@ -1063,26 +1064,29 @@ where /// use range_bounds_map::RangeBoundsMap; /// /// let mut map = - /// RangeBoundsMap::from_slice_strict([(1..4, false)]).unwrap(); + /// RangeBoundsMap::from_slice_strict([(ie(1, 4), false)]).unwrap(); /// /// // Touching /// assert_eq!( - /// map.insert_merge_overlapping(-4..1, true), - /// Ok(&(-4..1)) + /// map.insert_merge_overlapping(ie(-4, 1), true), + /// Ok(ie(-4, 1)) /// ); /// /// // Overlapping - /// assert_eq!(map.insert_merge_overlapping(2..8, true), Ok(&(1..8))); + /// assert_eq!( + /// map.insert_merge_overlapping(ie(2, 8), true), + /// Ok(ie(1, 8)) + /// ); /// /// // Neither Touching or Overlapping /// assert_eq!( - /// map.insert_merge_overlapping(10..16, false), - /// Ok(&(10..16)) + /// map.insert_merge_overlapping(ie(10, 16), false), + /// Ok(ie(0, 6)) /// ); /// /// assert_eq!( /// map.iter().collect::>(), - /// [(&(-4..1), &true), (&(1..8), &true), (&(10..16), &false)] + /// [(ie(-4, 1), &true), (ie(1, 8), &true), (ie(0, 6), &false)] /// ); /// ``` pub fn insert_merge_overlapping( @@ -1124,29 +1128,29 @@ where /// use range_bounds_map::RangeBoundsMap; /// /// let mut map = - /// RangeBoundsMap::from_slice_strict([(1..4, false)]).unwrap(); + /// RangeBoundsMap::from_slice_strict([(ie(1, 4), false)]).unwrap(); /// /// // Touching /// assert_eq!( - /// map.insert_merge_touching_or_overlapping(-4..1, true), - /// Ok(&(-4..4)) + /// map.insert_merge_touching_or_overlapping(ie(-4, 1), true), + /// Ok(ie(-4, 4)) /// ); /// /// // Overlapping /// assert_eq!( - /// map.insert_merge_touching_or_overlapping(2..8, true), - /// Ok(&(-4..8)) + /// map.insert_merge_touching_or_overlapping(ie(2, 8), true), + /// Ok(ie(-4, 8)) /// ); /// /// // Neither Touching or Overlapping /// assert_eq!( - /// map.insert_merge_touching_or_overlapping(10..16, false), - /// Ok(&(10..16)) + /// map.insert_merge_touching_or_overlapping(ie(10, 16), false), + /// Ok(ie(0, 6)) /// ); /// /// assert_eq!( /// map.iter().collect::>(), - /// [(&(-4..8), &true), (&(10..16), &false)] + /// [(ie(-4, 8), &true), (ie(0, 6), &false)] /// ); /// ``` pub fn insert_merge_touching_or_overlapping( @@ -1186,13 +1190,13 @@ where /// use range_bounds_map::RangeBoundsMap; /// /// let mut map = - /// RangeBoundsMap::from_slice_strict([(2..8, false)]).unwrap(); + /// RangeBoundsMap::from_slice_strict([(ie(2, 8), false)]).unwrap(); /// - /// assert_eq!(map.insert_overwrite(4..6, true), Ok(())); + /// assert_eq!(map.insert_overwrite(ie(4, 6), true), Ok(())); /// /// assert_eq!( /// map.iter().collect::>(), - /// [(&(2..4), &false), (&(4..6), &true), (&(6..8), &false)] + /// [(ie(2, 4), &false), (ie(4, 6), &true), (ie(6, 8), &false)] /// ); /// ``` pub fn insert_overwrite( @@ -1217,13 +1221,13 @@ where /// use range_bounds_map::RangeBoundsMap; /// /// let map = RangeBoundsMap::from_slice_strict([ - /// (1..4, false), - /// (4..8, true), - /// (8..100, false), + /// (ie(1, 4), false), + /// (ie(4, 8), true), + /// (ie(8, 100), false), /// ]) /// .unwrap(); /// - /// assert_eq!(map.first_entry(), Some((&(1..4), &false))); + /// assert_eq!(map.first_entry(), Some((ie(1, 4), &false))); /// ``` pub fn first_entry(&self) -> Option<(&K, &V)> { self.inner.first_key_value() @@ -1237,19 +1241,29 @@ where /// use range_bounds_map::RangeBoundsMap; /// /// let map = RangeBoundsMap::from_slice_strict([ - /// (1..4, false), - /// (4..8, true), - /// (8..100, false), + /// (ie(1, 4), false), + /// (ie(4, 8), true), + /// (ie(8, 100), false), /// ]) /// .unwrap(); /// /// assert_eq!( /// map.last_entry(), - /// Some((&(8..100), &false)) + /// Some((ie(8, 0), &false)) /// ); pub fn last_entry(&self) -> Option<(&K, &V)> { self.inner.last_key_value() } + + pub fn from_slice_strict( + slice: [(K, V); N], + ) -> Result, OverlapError> { + let mut map = RangeBoundsMap::new(); + for (range, value) in slice { + map.insert_strict(range, value)?; + } + return Ok(map); + } } fn overlapping_start_comp(start: Bound) -> impl FnMut(&K) -> Ordering @@ -1399,3 +1413,1011 @@ where self.end_bound().cloned() } } + +#[cfg(test)] +mod tests { + use std::ops::Bound; + + use pretty_assertions::assert_eq; + + use super::*; + use crate::bound_ord::BoundOrd; + use crate::helpers::{config, touches, Config, CutResult}; + + type TestBounds = (Bound, Bound); + + //only every other number to allow mathematical_overlapping_definition + //to test between bounds in finite using smaller intervalled finite + pub(crate) const NUMBERS: &'static [u8] = &[2, 4, 6, 8, 10]; + //go a bit around on either side to compensate for Unbounded + pub(crate) const NUMBERS_DOMAIN: &'static [u8] = + &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]; + + fn basic() -> RangeBoundsMap { + RangeBoundsMap::from_slice_strict([ + (ui(4), false), + (ee(5, 7), true), + (ii(7, 7), false), + (ie(14, 16), true), + ]) + .unwrap() + } + + fn special() -> RangeBoundsMap { + RangeBoundsMap::from_slice_strict([ + (mii(4, 6), false), + (mee(7, 8), true), + (mii(8, 12), false), + ]) + .unwrap() + } + + #[derive(Debug, PartialEq, Copy, Clone)] + enum MultiBounds { + Inclusive(u8, u8), + Exclusive(u8, u8), + } + + fn mii(start: u8, end: u8) -> MultiBounds { + MultiBounds::Inclusive(start, end) + } + fn mee(start: u8, end: u8) -> MultiBounds { + MultiBounds::Exclusive(start, end) + } + + impl RangeBounds for MultiBounds { + fn start_bound(&self) -> Bound<&u8> { + match self { + MultiBounds::Inclusive(start, _) => Bound::Included(start), + MultiBounds::Exclusive(start, _) => Bound::Excluded(start), + } + } + fn end_bound(&self) -> Bound<&u8> { + match self { + MultiBounds::Inclusive(_, end) => Bound::Included(end), + MultiBounds::Exclusive(_, end) => Bound::Excluded(end), + } + } + } + impl TryFromBounds for MultiBounds { + fn try_from_bounds( + start_bound: Bound, + end_bound: Bound, + ) -> Result { + match (start_bound, end_bound) { + (Bound::Included(start), Bound::Included(end)) => { + Ok(mii(start, end)) + } + (Bound::Excluded(start), Bound::Excluded(end)) => { + Ok(mee(start, end)) + } + _ => Err(TryFromBoundsError), + } + } + } + + #[test] + fn insert_strict_tests() { + assert_insert_strict( + basic(), + (ii(0, 4), false), + Err(OverlapError), + None::<[_; 0]>, + ); + assert_insert_strict( + basic(), + (ii(5, 6), false), + Err(OverlapError), + None::<[_; 0]>, + ); + assert_insert_strict( + basic(), + (ee(7, 8), false), + Ok(()), + Some([ + (ui(4), false), + (ee(5, 7), true), + (ii(7, 7), false), + (ee(7, 8), false), + (ie(14, 16), true), + ]), + ); + assert_insert_strict( + basic(), + (ii(4, 5), true), + Err(OverlapError), + None::<[_; 0]>, + ); + assert_insert_strict( + basic(), + (ei(4, 5), true), + Ok(()), + Some([ + (ui(4), false), + (ei(4, 5), true), + (ee(5, 7), true), + (ii(7, 7), false), + (ie(14, 16), true), + ]), + ); + } + fn assert_insert_strict( + mut before: RangeBoundsMap, + to_insert: (TestBounds, bool), + result: Result<(), OverlapError>, + after: Option<[(TestBounds, bool); N]>, + ) { + let clone = before.clone(); + assert_eq!(before.insert_strict(to_insert.0, to_insert.1), result); + match after { + Some(after) => { + assert_eq!( + before, + RangeBoundsMap::from_slice_strict(after).unwrap() + ) + } + None => assert_eq!(before, clone), + } + } + + #[test] + fn overlapping_tests() { + //case zero + for overlap_range in all_valid_test_bounds() { + //you can't overlap nothing + assert!( + RangeBoundsMap::::new() + .overlapping(overlap_range) + .next() + .is_none() + ); + } + + //case one + for overlap_range in all_valid_test_bounds() { + for inside_range in all_valid_test_bounds() { + let mut map = RangeBoundsMap::new(); + map.insert_strict(inside_range, ()).unwrap(); + + let mut expected_overlapping = Vec::new(); + if overlaps(overlap_range, inside_range) { + expected_overlapping.push(inside_range); + } + + let overlapping = map + .overlapping(overlap_range) + .map(|(key, _)| key) + .copied() + .collect::>(); + + if overlapping != expected_overlapping { + dbg!(overlap_range, inside_range); + dbg!(overlapping, expected_overlapping); + panic!( + "Discrepency in .overlapping() with single inside range detected!" + ); + } + } + } + + //case two + for overlap_range in all_valid_test_bounds() { + for (inside_range1, inside_range2) in + all_non_overlapping_test_bound_entries() + { + let mut map = RangeBoundsMap::new(); + map.insert_strict(inside_range1, ()).unwrap(); + map.insert_strict(inside_range2, ()).unwrap(); + + let mut expected_overlapping = Vec::new(); + if overlaps(overlap_range, inside_range1) { + expected_overlapping.push(inside_range1); + } + if overlaps(overlap_range, inside_range2) { + expected_overlapping.push(inside_range2); + } + //make our expected_overlapping the correct order + if expected_overlapping.len() > 1 { + if BoundOrd::start(expected_overlapping[0].start_bound()) + > BoundOrd::start(expected_overlapping[1].start_bound()) + { + expected_overlapping.swap(0, 1); + } + } + + let overlapping = map + .overlapping(overlap_range) + .map(|(key, _)| key) + .copied() + .collect::>(); + + if overlapping != expected_overlapping { + dbg!(overlap_range, inside_range1, inside_range2); + dbg!(overlapping, expected_overlapping); + panic!( + "Discrepency in .overlapping() with two inside ranges detected!" + ); + } + } + } + } + + #[test] + fn remove_overlapping_tests() { + assert_remove_overlapping(basic(), ii(5, 5), [], None::<[_; 0]>); + assert_remove_overlapping( + basic(), + uu(), + [ + (ui(4), false), + (ee(5, 7), true), + (ii(7, 7), false), + (ie(14, 16), true), + ], + Some([]), + ); + assert_remove_overlapping( + basic(), + ii(6, 7), + [(ee(5, 7), true), (ii(7, 7), false)], + Some([(ui(4), false), (ie(14, 16), true)]), + ); + assert_remove_overlapping( + basic(), + iu(6), + [(ee(5, 7), true), (ii(7, 7), false), (ie(14, 16), true)], + Some([(ui(4), false)]), + ); + } + fn assert_remove_overlapping( + mut before: RangeBoundsMap, + to_remove: TestBounds, + result: [(TestBounds, bool); N], + after: Option<[(TestBounds, bool); Y]>, + ) { + let clone = before.clone(); + assert_eq!( + before.remove_overlapping(to_remove).collect::>(), + result + ); + match after { + Some(after) => { + assert_eq!( + before, + RangeBoundsMap::from_slice_strict(after).unwrap() + ) + } + None => assert_eq!(before, clone), + } + } + + #[test] + fn cut_tests() { + assert_cut(basic(), ii(50, 60), Ok([]), None::<[_; 0]>); + assert_cut( + basic(), + uu(), + Ok([ + (ui(4), false), + (ee(5, 7), true), + (ii(7, 7), false), + (ie(14, 16), true), + ]), + Some([]), + ); + assert_cut( + basic(), + ui(6), + Ok([(ui(4), false), (ei(5, 6), true)]), + Some([(ee(6, 7), true), (ii(7, 7), false), (ie(14, 16), true)]), + ); + assert_cut( + basic(), + iu(6), + Ok([(ie(6, 7), true), (ii(7, 7), false), (ie(14, 16), true)]), + Some([(ui(4), false), (ee(5, 6), true)]), + ); + + assert_cut( + special(), + mee(5, 7), + Ok([((Bound::Excluded(5), Bound::Included(6)), false)]), + Some([(mii(4, 5), false), (mee(7, 8), true), (mii(8, 12), false)]), + ); + assert_cut(special(), mee(6, 7), Ok([]), None::<[_; 0]>); + assert_cut( + special(), + mii(5, 6), + Err::<[_; 0], _>(TryFromBoundsError), + None::<[_; 0]>, + ); + assert_cut( + special(), + mii(6, 7), + Err::<[_; 0], _>(TryFromBoundsError), + None::<[_; 0]>, + ); + assert_cut( + special(), + ie(7, 8), + Ok([((ee(7, 8)), true)]), + Some([(mii(4, 6), false), (mii(8, 12), false)]), + ); + assert_cut( + special(), + mii(7, 10), + Err::<[_; 0], _>(TryFromBoundsError), + None::<[_; 0]>, + ); + assert_cut( + special(), + mee(4, 6), + Ok([(ee(4, 6), false)]), + Some([ + (mii(4, 4), false), + (mii(6, 6), false), + (mee(7, 8), true), + (mii(8, 12), false), + ]), + ); + } + + fn assert_cut( + mut before: RangeBoundsMap, + to_cut: Q, + result: Result<[((Bound, Bound), V); Y], TryFromBoundsError>, + after: Option<[(K, V); N]>, + ) where + I: Ord + Debug + Copy, + K: NiceRange + TryFromBounds + PartialEq + Debug, + Q: NiceRange, + V: PartialEq + Debug + Clone, + { + let clone = before.clone(); + match before.cut(to_cut) { + Ok(iter) => { + assert_eq!(iter.collect::>(), result.unwrap()); + } + Err(x) => { + assert_eq!(x, result.unwrap_err()); + } + } + match after { + Some(after) => { + assert_eq!( + before, + RangeBoundsMap::from_slice_strict(after).unwrap() + ) + } + None => assert_eq!(before, clone), + } + } + + #[test] + fn gaps_tests() { + assert_gaps(basic(), ii(50, 60), [ii(50, 60)]); + assert_gaps(basic(), iu(50), [iu(50)]); + assert_gaps(basic(), ee(3, 16), [ei(4, 5), ee(7, 14)]); + assert_gaps(basic(), ei(3, 16), [ei(4, 5), ee(7, 14), ii(16, 16)]); + assert_gaps(basic(), ue(5), [ee(4, 5)]); + assert_gaps(basic(), ui(3), []); + assert_gaps(basic(), ii(5, 5), [ii(5, 5)]); + assert_gaps(basic(), ii(6, 6), []); + assert_gaps(basic(), ii(7, 7), []); + assert_gaps(basic(), ii(8, 8), [ii(8, 8)]); + } + fn assert_gaps( + map: RangeBoundsMap, + outer_range_bounds: TestBounds, + result: [TestBounds; N], + ) { + assert_eq!( + map.gaps(outer_range_bounds) + .map(|(start, end)| (start, end)) + .collect::>(), + result + ); + } + + #[test] + fn insert_merge_touching_tests() { + assert_insert_merge_touching( + basic(), + (ii(0, 4), false), + Err(OverlapOrTryFromBoundsError::Overlap(OverlapError)), + None::<[_; 0]>, + ); + assert_insert_merge_touching( + basic(), + (ee(7, 10), false), + Ok(ie(7, 10)), + Some([ + (ui(4), false), + (ee(5, 7), true), + (ie(7, 10), false), + (ie(14, 16), true), + ]), + ); + assert_insert_merge_touching( + basic(), + (ee(7, 11), true), + Ok(ie(7, 11)), + Some([ + (ui(4), false), + (ee(5, 7), true), + (ie(7, 11), true), + (ie(14, 16), true), + ]), + ); + assert_insert_merge_touching( + basic(), + (ee(12, 13), true), + Ok(ee(12, 13)), + Some([ + (ui(4), false), + (ee(5, 7), true), + (ii(7, 7), false), + (ee(12, 13), true), + (ie(14, 16), true), + ]), + ); + assert_insert_merge_touching( + basic(), + (ee(13, 14), false), + Ok(ee(13, 16)), + Some([ + (ui(4), false), + (ee(5, 7), true), + (ii(7, 7), false), + (ee(13, 16), false), + ]), + ); + assert_insert_merge_touching( + basic(), + (ee(7, 14), false), + Ok(ie(7, 16)), + Some([(ui(4), false), (ee(5, 7), true), (ie(7, 16), false)]), + ); + + assert_insert_merge_touching( + special(), + (mee(6, 7), true), + Err(OverlapOrTryFromBoundsError::TryFromBounds( + TryFromBoundsError, + )), + None::<[_; 0]>, + ); + assert_insert_merge_touching( + special(), + (mii(6, 7), true), + Err(OverlapOrTryFromBoundsError::Overlap(OverlapError)), + None::<[_; 0]>, + ); + assert_insert_merge_touching( + special(), + (mee(12, 15), true), + Err(OverlapOrTryFromBoundsError::TryFromBounds( + TryFromBoundsError, + )), + None::<[_; 0]>, + ); + assert_insert_merge_touching( + special(), + (mii(12, 15), true), + Err(OverlapOrTryFromBoundsError::Overlap(OverlapError)), + None::<[_; 0]>, + ); + } + fn assert_insert_merge_touching( + mut before: RangeBoundsMap, + to_insert: (K, V), + result: Result, + after: Option<[(K, V); N]>, + ) where + I: Ord + Debug + Copy, + K: NiceRange + TryFromBounds + PartialEq + Debug, + V: PartialEq + Debug + Clone, + { + let clone = before.clone(); + assert_eq!( + before.insert_merge_touching(to_insert.0, to_insert.1), + result + ); + match after { + Some(after) => { + assert_eq!( + before, + RangeBoundsMap::from_slice_strict(after).unwrap() + ) + } + None => assert_eq!(before, clone), + } + } + + #[test] + fn insert_merge_overlapping_tests() { + assert_insert_merge_overlapping( + basic(), + (ii(0, 2), true), + Ok(ui(4)), + Some([ + (ui(4), true), + (ee(5, 7), true), + (ii(7, 7), false), + (ie(14, 16), true), + ]), + ); + assert_insert_merge_overlapping( + basic(), + (ie(14, 16), false), + Ok(ie(14, 16)), + Some([ + (ui(4), false), + (ee(5, 7), true), + (ii(7, 7), false), + (ie(14, 16), false), + ]), + ); + assert_insert_merge_overlapping( + basic(), + (ii(6, 11), false), + Ok(ei(5, 11)), + Some([(ui(4), false), (ei(5, 11), false), (ie(14, 16), true)]), + ); + assert_insert_merge_overlapping( + basic(), + (ii(15, 18), true), + Ok(ii(14, 18)), + Some([ + (ui(4), false), + (ee(5, 7), true), + (ii(7, 7), false), + (ii(14, 18), true), + ]), + ); + assert_insert_merge_overlapping( + basic(), + (uu(), false), + Ok(uu()), + Some([(uu(), false)]), + ); + + assert_insert_merge_overlapping( + special(), + (mii(10, 18), true), + Ok(mii(8, 18)), + Some([(mii(4, 6), false), (mee(7, 8), true), (mii(8, 18), true)]), + ); + assert_insert_merge_overlapping( + special(), + (mee(10, 18), true), + Err(TryFromBoundsError), + None::<[_; 0]>, + ); + assert_insert_merge_overlapping( + special(), + (mee(8, 12), true), + Ok(mii(8, 12)), + Some([(mii(4, 6), false), (mee(7, 8), true), (mii(8, 12), true)]), + ); + assert_insert_merge_overlapping( + special(), + (mee(7, 8), false), + Ok(mee(7, 8)), + Some([(mii(4, 6), false), (mee(7, 8), false), (mii(8, 12), false)]), + ); + assert_insert_merge_overlapping( + special(), + (mii(7, 8), false), + Ok(mii(7, 12)), + Some([(mii(4, 6), false), (mii(7, 12), false)]), + ); + } + fn assert_insert_merge_overlapping( + mut before: RangeBoundsMap, + to_insert: (K, V), + result: Result, + after: Option<[(K, V); N]>, + ) where + I: Ord + Debug + Copy, + K: NiceRange + TryFromBounds + PartialEq + Debug, + V: PartialEq + Debug + Clone, + { + let clone = before.clone(); + assert_eq!( + before.insert_merge_overlapping(to_insert.0, to_insert.1), + result + ); + match after { + Some(after) => { + assert_eq!( + before, + RangeBoundsMap::from_slice_strict(after).unwrap() + ) + } + None => assert_eq!(before, clone), + } + } + + #[test] + fn insert_merge_touching_or_overlapping_tests() { + assert_insert_merge_touching_or_overlapping( + RangeBoundsMap::from_slice_strict([(ie(1, 4), false)]).unwrap(), + (ie(0, 1), true), + Ok(ie(0, 4)), + Some([(ie(0, 4), true)]), + ); + + //copied from insert_merge_overlapping_tests + assert_insert_merge_touching_or_overlapping( + basic(), + (ii(0, 2), true), + Ok(ui(4)), + Some([ + (ui(4), true), + (ee(5, 7), true), + (ii(7, 7), false), + (ie(14, 16), true), + ]), + ); + assert_insert_merge_touching_or_overlapping( + basic(), + (ie(14, 16), false), + Ok(ie(14, 16)), + Some([ + (ui(4), false), + (ee(5, 7), true), + (ii(7, 7), false), + (ie(14, 16), false), + ]), + ); + assert_insert_merge_touching_or_overlapping( + basic(), + (ii(6, 11), false), + Ok(ei(5, 11)), + Some([(ui(4), false), (ei(5, 11), false), (ie(14, 16), true)]), + ); + assert_insert_merge_touching_or_overlapping( + basic(), + (ii(15, 18), true), + Ok(ii(14, 18)), + Some([ + (ui(4), false), + (ee(5, 7), true), + (ii(7, 7), false), + (ii(14, 18), true), + ]), + ); + assert_insert_merge_touching_or_overlapping( + basic(), + (uu(), false), + Ok(uu()), + Some([(uu(), false)]), + ); + //the only difference from the insert_merge_overlapping + assert_insert_merge_touching_or_overlapping( + basic(), + (ii(7, 14), false), + Ok(ee(5, 16)), + Some([(ui(4), false), (ee(5, 16), false)]), + ); + + //copied from insert_merge_overlapping_tests + assert_insert_merge_touching_or_overlapping( + special(), + (mii(10, 18), true), + Ok(mii(8, 18)), + Some([(mii(4, 6), false), (mee(7, 8), true), (mii(8, 18), true)]), + ); + assert_insert_merge_touching_or_overlapping( + special(), + (mee(10, 18), true), + Err(TryFromBoundsError), + None::<[_; 0]>, + ); + assert_insert_merge_touching_or_overlapping( + special(), + (mee(8, 12), true), + Ok(mii(8, 12)), + Some([(mii(4, 6), false), (mee(7, 8), true), (mii(8, 12), true)]), + ); + assert_insert_merge_touching_or_overlapping( + special(), + (mee(7, 8), false), + Err(TryFromBoundsError), + None::<[_; 0]>, + ); + assert_insert_merge_touching_or_overlapping( + special(), + (mii(7, 8), false), + Ok(mii(7, 12)), + Some([(mii(4, 6), false), (mii(7, 12), false)]), + ); + //copied from insert_merge_touching_tests + assert_insert_merge_touching_or_overlapping( + special(), + (mee(6, 7), true), + Err(TryFromBoundsError), + None::<[_; 0]>, + ); + assert_insert_merge_touching_or_overlapping( + special(), + (mee(12, 15), true), + Err(TryFromBoundsError), + None::<[_; 0]>, + ); + } + fn assert_insert_merge_touching_or_overlapping( + mut before: RangeBoundsMap, + to_insert: (K, V), + result: Result, + after: Option<[(K, V); N]>, + ) where + I: Ord + Debug + Copy, + K: NiceRange + TryFromBounds + PartialEq + Debug, + V: PartialEq + Debug + Clone, + { + let clone = before.clone(); + assert_eq!( + before + .insert_merge_touching_or_overlapping(to_insert.0, to_insert.1), + result + ); + match after { + Some(after) => { + assert_eq!( + before, + RangeBoundsMap::from_slice_strict(after).unwrap() + ) + } + None => assert_eq!(before, clone), + } + } + + #[test] + fn config_tests() { + assert_eq!(config(ie(1, 4), ie(6, 8)), Config::LeftFirstNonOverlapping); + assert_eq!(config(ie(1, 4), ie(2, 8)), Config::LeftFirstPartialOverlap); + assert_eq!(config(ie(1, 4), ie(2, 3)), Config::LeftContainsRight); + + assert_eq!( + config(ie(6, 8), ie(1, 4)), + Config::RightFirstNonOverlapping + ); + assert_eq!( + config(ie(2, 8), ie(1, 4)), + Config::RightFirstPartialOverlap + ); + assert_eq!(config(ie(2, 3), ie(1, 4)), Config::RightContainsLeft); + } + + #[test] + fn overlaps_tests() { + for range_bounds1 in all_valid_test_bounds() { + for range_bounds2 in all_valid_test_bounds() { + let our_answer = overlaps(range_bounds1, range_bounds2); + + let mathematical_definition_of_overlap = + NUMBERS_DOMAIN.iter().any(|x| { + range_bounds1.contains(x) && range_bounds2.contains(x) + }); + + if our_answer != mathematical_definition_of_overlap { + dbg!(range_bounds1, range_bounds2); + dbg!(mathematical_definition_of_overlap, our_answer); + panic!("Discrepency in overlaps() detected!"); + } + } + } + } + + #[test] + fn cut_range_tests() { + for base in all_valid_test_bounds() { + for cut in all_valid_test_bounds() { + let cut_result @ CutResult { + before_cut: b, + inside_cut: i, + after_cut: a, + } = cut_range(base, cut); + + let mut on_left = true; + + // The definition of a cut is: A && NOT B + for x in NUMBERS_DOMAIN { + let base_contains = base.contains(x); + let cut_contains = cut.contains(x); + + if cut_contains { + on_left = false; + } + + let invariant = match (base_contains, cut_contains) { + (false, _) => !con(b, x) && !con(i, x) && !con(a, x), + (true, false) => { + if on_left { + con(b, x) && !con(i, x) && !con(a, x) + } else { + !con(b, x) && !con(i, x) && con(a, x) + } + } + (true, true) => !con(b, x) && con(i, x) && !con(a, x), + }; + + if !invariant { + dbg!(base_contains); + dbg!(cut_contains); + + dbg!(on_left); + + dbg!(base); + dbg!(cut); + dbg!(cut_result); + + dbg!(x); + + panic!("Invariant Broken!"); + } + } + } + } + } + fn con(x: Option<(Bound, Bound)>, point: &u8) -> bool { + match x { + Some(y) => y.contains(point), + None => false, + } + } + #[test] + fn cut_range_bounds_should_return_valid_ranges() { + let result: CutResult = cut_range(ie(3, 8), ie(5, 8)); + if let Some(x) = result.before_cut { + assert!(is_valid_range(x)); + } + if let Some(x) = result.inside_cut { + assert!(is_valid_range(x)); + } + if let Some(x) = result.after_cut { + assert!(is_valid_range(x)); + } + + let result = cut_range(ie(3, 8), ie(3, 5)); + if let Some(x) = result.before_cut { + assert!(is_valid_range(x)); + } + if let Some(x) = result.inside_cut { + assert!(is_valid_range(x)); + } + if let Some(x) = result.after_cut { + assert!(is_valid_range(x)); + } + } + + #[test] + fn touches_tests() { + for range_bounds1 in all_valid_test_bounds() { + for range_bounds2 in all_valid_test_bounds() { + let our_answer = touches(range_bounds1, range_bounds2); + + let mathematical_definition_of_touches = + NUMBERS_DOMAIN.iter().tuple_windows().any(|(x1, x2)| { + (range_bounds1.contains(x1) + && !range_bounds1.contains(x2) + && range_bounds2.contains(x2) + && !range_bounds2.contains(x1)) + || (range_bounds1.contains(x2) + && !range_bounds1.contains(x1) && range_bounds2 + .contains(x1) && !range_bounds2.contains(x2)) + }); + + if our_answer != mathematical_definition_of_touches { + dbg!(range_bounds1, range_bounds2); + dbg!(mathematical_definition_of_touches, our_answer); + panic!("Discrepency in touches() detected!"); + } + } + } + } + + // Test Helper Functions + //====================== + fn all_non_overlapping_test_bound_entries() -> Vec<(TestBounds, TestBounds)> + { + let mut output = Vec::new(); + for test_bounds1 in all_valid_test_bounds() { + for test_bounds2 in all_valid_test_bounds() { + if !overlaps(test_bounds1, test_bounds2) { + output.push((test_bounds1, test_bounds2)); + } + } + } + + return output; + } + + fn all_valid_test_bounds() -> Vec { + let mut output = Vec::new(); + + //bounded-bounded + output.append(&mut all_finite_bounded_entries()); + //bounded-unbounded + for start_bound in all_finite_bounded() { + output.push((start_bound, u())); + } + //unbounded-bounded + for end_bound in all_finite_bounded() { + output.push((u(), end_bound)); + } + //unbounded-unbounded + output.push(uu()); + + return output; + } + + fn all_finite_bounded_entries() -> Vec<(Bound, Bound)> { + let mut output = Vec::new(); + for i in NUMBERS { + for j in NUMBERS { + for i_ex in [false, true] { + for j_ex in [false, true] { + if j > i || (j == i && !i_ex && !j_ex) { + output.push(( + finite_bound(*i, i_ex), + finite_bound(*j, j_ex), + )); + } + } + } + } + } + return output; + } + + fn all_finite_bounded() -> Vec> { + let mut output = Vec::new(); + for i in NUMBERS { + for j in 0..=1 { + output.push(finite_bound(*i, j == 1)); + } + } + return output; + } + + fn finite_bound(x: u8, included: bool) -> Bound { + match included { + false => Bound::Included(x), + true => Bound::Excluded(x), + } + } + + fn uu() -> TestBounds { + (Bound::Unbounded, Bound::Unbounded) + } + fn ui(x: u8) -> TestBounds { + (Bound::Unbounded, Bound::Included(x)) + } + fn ue(x: u8) -> TestBounds { + (Bound::Unbounded, Bound::Excluded(x)) + } + fn iu(x: u8) -> TestBounds { + (Bound::Included(x), Bound::Unbounded) + } + //fn eu(x: u8) -> TestBounds { + //(Bound::Excluded(x), Bound::Unbounded) + //} + fn ii(x1: u8, x2: u8) -> TestBounds { + (Bound::Included(x1), Bound::Included(x2)) + } + fn ie(x1: u8, x2: u8) -> TestBounds { + (Bound::Included(x1), Bound::Excluded(x2)) + } + fn ei(x1: u8, x2: u8) -> TestBounds { + (Bound::Excluded(x1), Bound::Included(x2)) + } + fn ee(x1: u8, x2: u8) -> TestBounds { + (Bound::Excluded(x1), Bound::Excluded(x2)) + } + fn u() -> Bound { + Bound::Unbounded + } +}