diff --git a/src/range_bounds_map.rs b/src/range_bounds_map.rs
index e81d49f..f80bf2a 100644
--- a/src/range_bounds_map.rs
+++ b/src/range_bounds_map.rs
@@ -17,7 +17,6 @@ You should have received a copy of the GNU General Public License
along with range_bounds_map. If not, see .
*/
-use std::cmp::Ordering;
use std::collections::BTreeMap;
use std::fmt::Debug;
use std::iter::once;
@@ -25,7 +24,7 @@ use std::ops::{Bound, RangeBounds};
use either::Either;
use itertools::Itertools;
-use labels::{tested, trivial};
+use labels::{tested, trivial, untested};
use serde::{Deserialize, Serialize};
use crate::bound_ord::BoundOrd;
@@ -647,15 +646,20 @@ where
return output.into_iter();
}
- /// Cuts a given `RangeBounds` out of the map.
+ /// Cuts a given `RangeBounds` out of the map and returns an
+ /// iterator of the full or partial `RangeBounds` that were cut in
+ /// a tuple with their `Value`s.
///
- /// If the remaining `RangeBounds` left after the cut are not able
- /// to be created with the [`TryFromBounds`] trait then a
+ /// If the remaining `RangeBounds` left in the map after the cut
+ /// or the `RangeBounds` returned in the iterator are not able to
+ /// be created with the [`TryFromBounds`] trait then a
/// [`TryFromBoundsError`] will be returned.
///
/// `V` must implement `Clone` as if you try to cut out the center
/// of a `RangeBounds` in the map it will split into two different
- /// (`RangeBounds`, `Value`) pairs using `Clone`.
+ /// (`RangeBounds`, `Value`) pairs using `Clone`. Or if you
+ /// partially cut a `RangeBounds` then `V` must be cloned to be
+ /// returned in the iterator.
///
/// # Examples
/// ```
@@ -676,74 +680,65 @@ where
/// assert_eq!(base, after_cut);
/// assert_eq!(base.cut(&(60..=80)), Err(TryFromBoundsError));
/// ```
- #[tested]
- pub fn cut(&mut self, range_bounds: &Q) -> Result<(), TryFromBoundsError>
- where
- Q: RangeBounds,
- K: TryFromBounds,
- V: Clone,
- {
- let mut to_insert = Vec::new();
+ //#[untested]
+ //pub fn cut(&mut self, range_bounds: &Q) -> Result<(), TryFromBoundsError>
+ //where
+ //Q: RangeBounds,
+ //K: TryFromBounds,
+ //V: Clone,
+ //{
+ //let mut to_insert = Vec::new();
- {
- // only the first and last range_bounds in overlapping stand a
- // change of remaining after the cut so we don't need to
- // collect the iterator and can just look at the first and
- // last elements since range is a double ended iterator ;p
- let mut overlapping = self.overlapping(range_bounds);
+ //{
+ //let mut overlapping = self.overlapping(range_bounds);
- let first_last = (overlapping.next(), overlapping.next_back());
+ //let first_last = (overlapping.next(), overlapping.next_back());
- match first_last {
- (Some(first), Some(last)) => {
- match cut_range_bounds(first.0, range_bounds) {
- CutResult::Nothing => {}
- CutResult::Single(left_section) => {
- to_insert.push((left_section, first.1.clone()));
- }
- CutResult::Double(_, _) => unreachable!(),
- }
- match cut_range_bounds(last.0, range_bounds) {
- CutResult::Nothing => {}
- CutResult::Single(right_section) => {
- to_insert.push((right_section, last.1.clone()));
- }
- CutResult::Double(_, _) => unreachable!(),
- }
- }
- (Some(first), None) => {
- match cut_range_bounds(first.0, range_bounds) {
- CutResult::Nothing => {}
- CutResult::Single(section) => {
- to_insert.push((section, first.1.clone()));
- }
- CutResult::Double(left_section, right_section) => {
- to_insert.push((left_section, first.1.clone()));
- to_insert.push((right_section, first.1.clone()));
- }
- }
- }
- (None, None) => {}
- (None, Some(_)) => unreachable!(),
- }
- }
+ //match first_last {
+ //(Some(first), Some(last)) => {
+ //match cut_range_bounds(first.0, range_bounds) {
+ //CutResult::Nothing => {}
+ //CutResult::Single(left_section) => {
+ //to_insert.push((left_section, first.1.clone()));
+ //}
+ //CutResult::Double(_, _) => unreachable!(),
+ //}
+ //match cut_range_bounds(last.0, range_bounds) {
+ //CutResult::Nothing => {}
+ //CutResult::Single(right_section) => {
+ //to_insert.push((right_section, last.1.clone()));
+ //}
+ //CutResult::Double(_, _) => unreachable!(),
+ //}
+ //(Some(first), None) => {
+ //match cut_range_bounds(first.0, range_bounds) {
+ //CutResult::Nothing => {}
+ //CutResult::Single(section) => {
+ //to_insert.push((section, first.1.clone()));
+ //}
+ //CutResult::Double(left_section, right_section) => {
+ //to_insert.push((left_section, first.1.clone()));
+ //to_insert.push((right_section, first.1.clone()));
+ //}
+ //(None, None) => {}
+ //(None, Some(_)) => unreachable!(),
+ //}
- // Make sure that the inserts will work before we try to do
- // them, so if one fails the map remains unchanged
- if to_insert.iter().all(|(x, _)| K::is_valid(x)) {
- self.remove_overlapping(range_bounds).next();
- for ((start, end), value) in to_insert.into_iter() {
- self.insert_platonic(
- K::try_from_bounds(start, end).unwrap(),
- value.clone(),
- )
- .unwrap();
- }
- return Ok(());
- } else {
- return Err(TryFromBoundsError);
- }
- }
+ //// Make sure that the inserts will work before we try to do
+ //// them, so if one fails the map remains unchanged
+ //if to_insert.iter().all(|(x, _)| K::is_valid(x)) {
+ //let removed = self.remove_overlapping(range_bounds);
+ //for ((start, end), value) in to_insert.into_iter() {
+ //self.insert_platonic(
+ //K::try_from_bounds(start, end).unwrap(),
+ //value.clone(),
+ //)
+ //.unwrap();
+ //}
+ //return Ok(());
+ //} else {
+ //return Err(TryFromBoundsError);
+ //}
/// Returns an iterator of `(Bound<&I>, Bound<&I>)` over all the
/// maximally-sized gaps in the map that are also within the given
@@ -1067,7 +1062,7 @@ where
.ok_or(TryFromBoundsError)?;
// Out with the old!
- self.remove_overlapping(&range_bounds).next();
+ let _ = self.remove_overlapping(&range_bounds);
// In with the new!
self.starts.insert(
@@ -1175,7 +1170,7 @@ where
K::try_from_bounds(start_bound.clone(), end_bound)
.ok_or(TryFromBoundsError)?;
- self.remove_overlapping(&new_range_bounds).next();
+ let _ = self.remove_overlapping(&new_range_bounds);
self.starts.insert(
BoundOrd::start(start_bound.clone()),
(new_range_bounds, value),
@@ -1210,21 +1205,21 @@ where
/// [(&(2..4), &false), (&(4..6), &true), (&(6..8), &false)]
/// );
/// ```
- #[trivial]
- pub fn overwrite(
- &mut self,
- range_bounds: K,
- value: V,
- ) -> Result<(), TryFromBoundsError>
- where
- V: Clone,
- K: TryFromBounds,
- {
- self.cut(&range_bounds)?;
- self.insert_platonic(range_bounds, value).unwrap();
+ //#[trivial]
+ //pub fn overwrite(
+ //&mut self,
+ //range_bounds: K,
+ //value: V,
+ //) -> Result<(), TryFromBoundsError>
+ //where
+ //V: Clone,
+ //K: TryFromBounds,
+ //{
+ //self.cut(&range_bounds)?;
+ //self.insert_platonic(range_bounds, value).unwrap();
- return Ok(());
- }
+ //return Ok(());
+ //}
/// Returns the first (`RangeBounds`, `Value`) pair in the map, if
/// any.
@@ -1317,62 +1312,153 @@ where
}
}
-#[derive(Debug)]
-enum CutResult {
- Nothing,
- Single((Bound, Bound)),
- Double((Bound, Bound), (Bound, Bound)),
+#[derive(Debug, PartialEq)]
+enum Config {
+ LeftFirstNonOverlapping((Bound, Bound), (Bound, Bound)),
+ LeftFirstPartialOverlap((Bound, Bound), (Bound, Bound)),
+ LeftContainsRight((Bound, Bound), (Bound, Bound)),
+
+ RightFirstNonOverlapping((Bound, Bound), (Bound, Bound)),
+ RightFirstPartialOverlap((Bound, Bound), (Bound, Bound)),
+ RightContainsLeft((Bound, Bound), (Bound, Bound)),
}
-#[tested]
-fn cut_range_bounds(
- base_range_bounds: &B,
- cut_range_bounds: &C,
-) -> CutResult
+#[untested]
+fn config<'a, I, A, B>(a: &'a A, b: &'a B) -> Config<&'a I>
+where
+ A: RangeBounds,
+ B: RangeBounds,
+ I: PartialOrd,
+{
+ let a_all @ (a_start, a_end) = (a.start_bound(), a.end_bound());
+ let b_all @ (b_start, b_end) = (b.start_bound(), b.end_bound());
+
+ match BoundOrd::start(a_start) < BoundOrd::start(b_start) {
+ true => {
+ match (
+ contains_bound_ord(a, BoundOrd::start(b_start)),
+ contains_bound_ord(a, BoundOrd::end(b_end)),
+ ) {
+ (false, false) => Config::LeftFirstNonOverlapping(a_all, b_all),
+ (true, false) => Config::LeftFirstPartialOverlap(a_all, b_all),
+ (true, true) => Config::LeftContainsRight(a_all, b_all),
+ (false, true) => unreachable!(),
+ }
+ }
+ false => {
+ match (
+ contains_bound_ord(b, BoundOrd::start(a_start)),
+ contains_bound_ord(b, BoundOrd::end(a_end)),
+ ) {
+ (false, false) => {
+ Config::RightFirstNonOverlapping(a_all, b_all)
+ }
+ (true, false) => Config::RightFirstPartialOverlap(a_all, b_all),
+ (true, true) => Config::RightContainsLeft(a_all, b_all),
+ (false, true) => unreachable!(),
+ }
+ }
+ }
+}
+
+#[derive(Debug, PartialEq)]
+enum SortedConfig {
+ NonOverlapping((Bound, Bound), (Bound, Bound)),
+ PartialOverlap((Bound, Bound), (Bound, Bound)),
+ Swallowed((Bound, Bound), (Bound, Bound)),
+}
+
+#[rustfmt::skip]
+#[untested]
+fn sorted_config<'a, I, A, B>(a: &'a A, b: &'a B) -> SortedConfig<&'a I>
+where
+ A: RangeBounds,
+ B: RangeBounds,
+ I: PartialOrd,
+{
+ match config(a, b) {
+ Config::LeftFirstNonOverlapping(a, b) => SortedConfig::NonOverlapping(a, b),
+ Config::LeftFirstPartialOverlap(a, b) => SortedConfig::Swallowed(a, b),
+ Config::LeftContainsRight(a, b) => SortedConfig::Swallowed(a, b),
+
+ Config::RightFirstNonOverlapping(a, b) => SortedConfig::NonOverlapping(b, a),
+ Config::RightFirstPartialOverlap(a, b) => SortedConfig::PartialOverlap(b, a),
+ Config::RightContainsLeft(a, b) => SortedConfig::Swallowed(b, a),
+ }
+}
+
+#[untested]
+fn contains_bound_ord(range_bounds: &A, bound_ord: BoundOrd<&I>) -> bool
+where
+ A: RangeBounds,
+ I: PartialOrd,
+{
+ let start_bound_ord = BoundOrd::start(range_bounds.start_bound());
+ let end_bound_ord = BoundOrd::end(range_bounds.end_bound());
+
+ return bound_ord >= start_bound_ord && bound_ord <= end_bound_ord;
+}
+
+#[derive(Debug)]
+enum CutResult {
+ Nothing((Bound, Bound)),
+ Everything((Bound, Bound)),
+ Single(SingleCutResult),
+ Double(DoubleCutResult),
+}
+
+#[derive(Debug)]
+struct SingleCutResult {
+ inside_cut: (Bound, Bound),
+ outside_cut: (Bound, Bound),
+}
+
+#[derive(Debug)]
+struct DoubleCutResult {
+ inside_cut: (Bound, Bound),
+ before_cut: (Bound, Bound),
+ after_cut: (Bound, Bound),
+}
+
+#[untested]
+fn cut_range_bounds<'a, I, B, C>(
+ base_range_bounds: &'a B,
+ cut_range_bounds: &'a C,
+) -> CutResult<&'a I>
where
B: RangeBounds,
C: RangeBounds,
I: PartialOrd + Clone,
{
- if !overlaps(base_range_bounds, cut_range_bounds) {
- // if they don't overlap just return the original
- // base_range_bounds
- return CutResult::Single((
- base_range_bounds.start_bound().cloned(),
- base_range_bounds.end_bound().cloned(),
- ));
- }
-
- let (base_start_bound, base_end_bound) = (
+ let base_all @ (base_start, base_end) = (
base_range_bounds.start_bound(),
base_range_bounds.end_bound(),
);
- let (cut_start_bound, cut_end_bound) =
+ let cut_all @ (cut_start, cut_end) =
(cut_range_bounds.start_bound(), cut_range_bounds.end_bound());
- let left_section = match BoundOrd::start(cut_start_bound)
- > BoundOrd::start(base_start_bound)
- {
- false => None,
- true => Some((
- base_start_bound.cloned(),
- flip_bound(cut_start_bound).cloned(),
- )),
- };
- let right_section = match BoundOrd::end(cut_end_bound)
- < BoundOrd::end(base_end_bound)
- {
- false => None,
- true => {
- Some((flip_bound(cut_end_bound).cloned(), base_end_bound.cloned()))
+ match config(base_range_bounds, cut_range_bounds) {
+ Config::LeftFirstNonOverlapping(_, _) => CutResult::Nothing(base_all),
+ Config::LeftFirstPartialOverlap(_, _) => {
+ CutResult::Single(SingleCutResult {
+ inside_cut: (cut_start, base_end),
+ outside_cut: (base_start, flip_bound(cut_start)),
+ })
}
- };
+ Config::LeftContainsRight(a, b) => CutResult::Double(DoubleCutResult {
+ inside_cut: cut_all,
+ before_cut: (base_start, flip_bound(cut_start)),
+ after_cut: (flip_bound(cut_end), base_end),
+ }),
- match (left_section, right_section) {
- (Some(left), Some(right)) => CutResult::Double(left, right),
- (Some(left), None) => CutResult::Single(left),
- (None, Some(right)) => CutResult::Single(right),
- (None, None) => CutResult::Nothing,
+ Config::RightFirstNonOverlapping(_, _) => CutResult::Nothing(base_all),
+ Config::RightFirstPartialOverlap(_, _) => {
+ CutResult::Single(SingleCutResult {
+ inside_cut: (base_start, cut_end),
+ outside_cut: (flip_bound(cut_end), base_end),
+ })
+ }
+ Config::RightContainsLeft(_, _) => CutResult::Everything(base_all),
}
}
@@ -1398,33 +1484,13 @@ where
B: RangeBounds,
I: PartialOrd,
{
- // optimisation, do this with much less operations
- let a_start = a.start_bound();
- let a_end = a.end_bound();
-
- let b_start = b.start_bound();
- let b_end = b.end_bound();
-
- let (left_end, right_start) =
- match BoundOrd::start(a_start).cmp(&BoundOrd::start(b_start)) {
- Ordering::Less => (a_end, b_start),
- Ordering::Greater => (b_end, a_start),
- Ordering::Equal => return true,
- };
-
- match (left_end, right_start) {
- (Bound::Included(end), Bound::Included(start)) => end >= start,
-
- (Bound::Excluded(end), Bound::Excluded(start)) => end > start,
- (Bound::Included(end), Bound::Excluded(start)) => end > start,
- (Bound::Excluded(end), Bound::Included(start)) => end > start,
-
- (Bound::Unbounded, _) => true,
-
- (_, Bound::Unbounded) => unreachable!(),
+ match sorted_config(a, b) {
+ SortedConfig::NonOverlapping(_, _) => false,
+ _ => true,
}
}
+#[rustfmt::skip]
#[tested]
fn touches(a: &A, b: &B) -> bool
where
@@ -1432,23 +1498,14 @@ where
B: RangeBounds,
I: PartialOrd,
{
- // optimisation, do this with much less operations
- let a_start = a.start_bound();
- let a_end = a.end_bound();
-
- let b_start = b.start_bound();
- let b_end = b.end_bound();
-
- let (left_end, right_start) =
- match BoundOrd::start(a_start).cmp(&BoundOrd::start(b_start)) {
- Ordering::Less => (a_end, b_start),
- Ordering::Greater => (b_end, a_start),
- Ordering::Equal => return false,
- };
-
- match (left_end, right_start) {
- (Bound::Included(end), Bound::Excluded(start)) => end == start,
- (Bound::Excluded(end), Bound::Included(start)) => end == start,
+ match sorted_config(a, b) {
+ SortedConfig::NonOverlapping(a, b) => {
+ match (a.1, b.0) {
+ (Bound::Included(point1), Bound::Excluded(point2)) => point1 == point2,
+ (Bound::Excluded(point1), Bound::Included(point2)) => point1 == point2,
+ _ => false,
+ }
+ }
_ => false,
}
}
@@ -1461,929 +1518,3 @@ fn flip_bound(bound: Bound<&I>) -> Bound<&I> {
Bound::Unbounded => Bound::Unbounded,
}
}
-
-#[cfg(test)]
-mod tests {
- use std::ops::{Bound, Range, RangeBounds};
-
- use pretty_assertions::assert_eq;
-
- use super::*;
- use crate::bound_ord::BoundOrd;
-
- 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::try_from([
- (ui(4), false),
- (ee(5, 7), true),
- (ii(7, 7), false),
- (ie(14, 16), true),
- ])
- .unwrap()
- }
-
- fn special() -> RangeBoundsMap {
- RangeBoundsMap::try_from([
- (mii(4, 6), false),
- (mee(7, 8), true),
- (mii(8, 12), false),
- ])
- .unwrap()
- }
-
- #[derive(Debug, PartialEq, 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,
- ) -> Option {
- match (start_bound, end_bound) {
- (Bound::Included(start), Bound::Included(end)) => {
- Some(mii(start, end))
- }
- (Bound::Excluded(start), Bound::Excluded(end)) => {
- Some(mee(start, end))
- }
- _ => None,
- }
- }
- }
-
- #[test]
- fn insert_platonic_tests() {
- assert_insert_platonic(
- basic(),
- (ii(0, 4), false),
- Err(OverlapError),
- None::<[_; 0]>,
- );
- assert_insert_platonic(
- basic(),
- (ii(5, 6), false),
- Err(OverlapError),
- None::<[_; 0]>,
- );
- assert_insert_platonic(
- 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_platonic(
- basic(),
- (ii(4, 5), true),
- Err(OverlapError),
- None::<[_; 0]>,
- );
- assert_insert_platonic(
- 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_platonic(
- mut before: RangeBoundsMap,
- to_insert: (TestBounds, bool),
- result: Result<(), OverlapError>,
- after: Option<[(TestBounds, bool); N]>,
- ) {
- let clone = before.clone();
- assert_eq!(before.insert_platonic(to_insert.0, to_insert.1), result);
- match after {
- Some(after) => {
- assert_eq!(before, RangeBoundsMap::try_from(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 range_bounds_set = RangeBoundsMap::new();
- range_bounds_set.insert_platonic(inside_range, ()).unwrap();
-
- let mut expected_overlapping = Vec::new();
- if overlaps(&overlap_range, &inside_range) {
- expected_overlapping.push(inside_range);
- }
-
- let overlapping = range_bounds_set
- .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_pairs()
- {
- let mut range_bounds_set = RangeBoundsMap::new();
- range_bounds_set.insert_platonic(inside_range1, ()).unwrap();
- range_bounds_set.insert_platonic(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 = range_bounds_set
- .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::try_from(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(()), Some([]));
- assert_cut(
- basic(),
- ui(6),
- Ok(()),
- Some([(ee(6, 7), true), (ii(7, 7), false), (ie(14, 16), true)]),
- );
- assert_cut(
- basic(),
- iu(6),
- Ok(()),
- Some([(ui(4), false), (ee(5, 6), true)]),
- );
-
- assert_cut(
- special(),
- mee(5, 7),
- Ok(()),
- 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(TryFromBoundsError),
- None::<[_; 0]>,
- );
- assert_cut(
- special(),
- mii(6, 7),
- Err(TryFromBoundsError),
- None::<[_; 0]>,
- );
- assert_cut(
- special(),
- 7..8,
- Ok(()),
- Some([(mii(4, 6), false), (mii(8, 12), false)]),
- );
- assert_cut(
- special(),
- mii(7, 10),
- Err(TryFromBoundsError),
- None::<[_; 0]>,
- );
- assert_cut(
- special(),
- mee(4, 6),
- Ok(()),
- 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<(), TryFromBoundsError>,
- after: Option<[(K, V); N]>,
- ) where
- I: Ord + Clone + Debug,
- K: Clone + TryFromBounds + Debug + PartialEq,
- V: Clone + Debug + PartialEq,
- K: RangeBounds,
- Q: RangeBounds,
- {
- let clone = before.clone();
- assert_eq!(before.cut(&to_cut), result);
- match after {
- Some(after) => {
- assert_eq!(before, RangeBoundsMap::try_from(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(
- range_bounds_map: RangeBoundsMap,
- outer_range_bounds: TestBounds,
- result: [TestBounds; N],
- ) {
- assert_eq!(
- range_bounds_map
- .gaps(&outer_range_bounds)
- .map(|(start, end)| (start.cloned(), end.cloned()))
- .collect::>(),
- result
- );
- }
-
- #[test]
- fn insert_coalesce_touching_tests() {
- assert_insert_coalesce_touching(
- basic(),
- (ii(0, 4), false),
- Err(OverlapOrTryFromBoundsError::Overlap(OverlapError)),
- None::<[_; 0]>,
- );
- assert_insert_coalesce_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_coalesce_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_coalesce_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_coalesce_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_coalesce_touching(
- basic(),
- (ee(7, 14), false),
- Ok(&ie(7, 16)),
- Some([(ui(4), false), (ee(5, 7), true), (ie(7, 16), false)]),
- );
-
- assert_insert_coalesce_touching(
- special(),
- (mee(6, 7), true),
- Err(OverlapOrTryFromBoundsError::TryFromBounds(
- TryFromBoundsError,
- )),
- None::<[_; 0]>,
- );
- assert_insert_coalesce_touching(
- special(),
- (mii(6, 7), true),
- Err(OverlapOrTryFromBoundsError::Overlap(OverlapError)),
- None::<[_; 0]>,
- );
- assert_insert_coalesce_touching(
- special(),
- (mee(12, 15), true),
- Err(OverlapOrTryFromBoundsError::TryFromBounds(
- TryFromBoundsError,
- )),
- None::<[_; 0]>,
- );
- assert_insert_coalesce_touching(
- special(),
- (mii(12, 15), true),
- Err(OverlapOrTryFromBoundsError::Overlap(OverlapError)),
- None::<[_; 0]>,
- );
- }
- fn assert_insert_coalesce_touching(
- mut before: RangeBoundsMap,
- to_insert: (K, V),
- result: Result<&K, OverlapOrTryFromBoundsError>,
- after: Option<[(K, V); N]>,
- ) where
- I: Ord + Clone + Debug,
- K: Clone + TryFromBounds + Debug + PartialEq,
- V: Clone + Debug + PartialEq,
- K: RangeBounds,
- {
- let clone = before.clone();
- assert_eq!(
- before.insert_coalesce_touching(to_insert.0, to_insert.1),
- result
- );
- match after {
- Some(after) => {
- assert_eq!(before, RangeBoundsMap::try_from(after).unwrap())
- }
- None => assert_eq!(before, clone),
- }
- }
-
- #[test]
- fn insert_coalesce_overlapping_tests() {
- assert_insert_coalesce_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_coalesce_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_coalesce_overlapping(
- basic(),
- (ii(6, 11), false),
- Ok(&ei(5, 11)),
- Some([(ui(4), false), (ei(5, 11), false), (ie(14, 16), true)]),
- );
- assert_insert_coalesce_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_coalesce_overlapping(
- basic(),
- (uu(), false),
- Ok(&uu()),
- Some([(uu(), false)]),
- );
-
- assert_insert_coalesce_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_coalesce_overlapping(
- special(),
- (mee(10, 18), true),
- Err(TryFromBoundsError),
- None::<[_; 0]>,
- );
- assert_insert_coalesce_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_coalesce_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_coalesce_overlapping(
- special(),
- (mii(7, 8), false),
- Ok(&mii(7, 12)),
- Some([(mii(4, 6), false), (mii(7, 12), false)]),
- );
- }
- fn assert_insert_coalesce_overlapping(
- mut before: RangeBoundsMap,
- to_insert: (K, V),
- result: Result<&K, TryFromBoundsError>,
- after: Option<[(K, V); N]>,
- ) where
- I: Ord + Clone + Debug,
- K: Clone + TryFromBounds + Debug + PartialEq,
- V: Clone + Debug + PartialEq,
- K: RangeBounds,
- {
- let clone = before.clone();
- assert_eq!(
- before.insert_coalesce_overlapping(to_insert.0, to_insert.1),
- result
- );
- match after {
- Some(after) => {
- assert_eq!(before, RangeBoundsMap::try_from(after).unwrap())
- }
- None => assert_eq!(before, clone),
- }
- }
-
- #[test]
- fn insert_coalesce_touching_or_overlapping_tests() {
- assert_insert_coalesce_touching_or_overlapping(
- RangeBoundsMap::try_from([(1..4, false)]).unwrap(),
- (-4..1, true),
- Ok(&(-4..4)),
- Some([(-4..4, true)]),
- );
-
- //copied from insert_coalesce_overlapping_tests
- assert_insert_coalesce_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_coalesce_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_coalesce_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_coalesce_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_coalesce_touching_or_overlapping(
- basic(),
- (uu(), false),
- Ok(&uu()),
- Some([(uu(), false)]),
- );
- //the only difference from the insert_coalesce_overlapping
- assert_insert_coalesce_touching_or_overlapping(
- basic(),
- (ii(7, 14), false),
- Ok(&ee(5, 16)),
- Some([(ui(4), false), (ee(5, 16), false)]),
- );
-
- //copied from insert_coalesce_overlapping_tests
- assert_insert_coalesce_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_coalesce_touching_or_overlapping(
- special(),
- (mee(10, 18), true),
- Err(TryFromBoundsError),
- None::<[_; 0]>,
- );
- assert_insert_coalesce_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_coalesce_touching_or_overlapping(
- special(),
- (mee(7, 8), false),
- Err(TryFromBoundsError),
- None::<[_; 0]>,
- );
- assert_insert_coalesce_touching_or_overlapping(
- special(),
- (mii(7, 8), false),
- Ok(&mii(7, 12)),
- Some([(mii(4, 6), false), (mii(7, 12), false)]),
- );
- //copied from insert_coalesce_touching_tests
- assert_insert_coalesce_touching_or_overlapping(
- special(),
- (mee(6, 7), true),
- Err(TryFromBoundsError),
- None::<[_; 0]>,
- );
- assert_insert_coalesce_touching_or_overlapping(
- special(),
- (mee(12, 15), true),
- Err(TryFromBoundsError),
- None::<[_; 0]>,
- );
- }
- fn assert_insert_coalesce_touching_or_overlapping(
- mut before: RangeBoundsMap,
- to_insert: (K, V),
- result: Result<&K, TryFromBoundsError>,
- after: Option<[(K, V); N]>,
- ) where
- I: Ord + Clone + Debug,
- K: Clone + TryFromBounds + Debug + PartialEq,
- V: Clone + Debug + PartialEq,
- K: RangeBounds,
- {
- let clone = before.clone();
- assert_eq!(
- before.insert_coalesce_touching_or_overlapping(
- to_insert.0,
- to_insert.1
- ),
- result
- );
- match after {
- Some(after) => {
- assert_eq!(before, RangeBoundsMap::try_from(after).unwrap())
- }
- None => assert_eq!(before, clone),
- }
- }
-
- #[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_bounds_tests() {
- for base in all_valid_test_bounds() {
- for cut in all_valid_test_bounds() {
- let cut_result = cut_range_bounds(&base, &cut);
-
- // The definition of a cut is: A && NOT B
- for x in NUMBERS_DOMAIN {
- let result_contains = cut_result.contains(x);
- let base_contains = base.contains(x);
- let cut_contains = cut.contains(x);
-
- let invariant =
- result_contains == (base_contains && !cut_contains);
-
- if !invariant {
- dbg!(result_contains);
- dbg!(base_contains);
- dbg!(cut_contains);
-
- dbg!(base);
- dbg!(cut);
- dbg!(cut_result);
-
- dbg!(x);
-
- panic!("Invariant Broken!");
- }
- }
- }
- }
- }
- impl CutResult {
- fn contains(&self, point: &I) -> bool
- where
- I: PartialOrd,
- {
- match self {
- CutResult::Nothing => false,
- CutResult::Single(range_bounds) => range_bounds.contains(point),
- CutResult::Double(first_range_bounds, second_range_bounds) => {
- first_range_bounds.contains(point)
- || second_range_bounds.contains(point)
- }
- }
- }
- }
-
- #[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_pairs() -> 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_pairs());
- //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_pairs() -> 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
- }
-}
diff --git a/todo.md b/todo.md
index d970e15..6a96c42 100644
--- a/todo.md
+++ b/todo.md
@@ -3,14 +3,26 @@
- try to fix all the uses of cloned() in the library
- make a StartBoundWrapper that uses StartBound to implement ord and
use that instead of storing the startbound twice
+- make a range_bounds configuration: NonOverlapping, A contained in B,
+ A partial overlap B, with A before B. And use it to simplify all the
+ logic based RangeBounds functions
# features
- make specifc RangeMap, RangeSet, RangeInclusiveMap... types for signature
simplification
+- alternatively add just the one generic SafeRangeBoundsMap + Set that
+ just add unwraps everywhere to simplify signatures on known-"Safe"
+ symmetric types such as Range
+
- add coalesce if same-value otherwise overwrite) function to make
finally make range_bounds_map a superset of rangemap
+- make cut() return and Ok(Iterator((Bound, Bound))) like gaps()
+- add gaps_same() and cut_same() which are gaps().map(to K) and
+ cut().map(to K) using TryFromBounds
+- update the TryFromBoundsError with examples of new gaps() and cut()
+
# time based
- use it in robot_Sweet_graph for a bit before publishing
@@ -22,6 +34,7 @@
- copy map to set again
- copy readme to lib.rs docs again
- take a look around idiomatic rust for a bit first
+- run is_labelled again
- review method parameter names for all public functions
- update lines of code figures on docs
- add issues to github for all the caveats