From 14e97347919236590a9bfe541080ccec3ffdf591 Mon Sep 17 00:00:00 2001 From: ripytide Date: Mon, 3 Apr 2023 17:59:46 +0100 Subject: [PATCH] omgosh cut is so pretty! everything compiles with a beautiful cut function written --- src/helpers.rs | 8 +-- src/range_bounds_map.rs | 110 ++++++++++++++++++++++++++++++++++------ src/try_from_bounds.rs | 59 +++++++++------------ 3 files changed, 122 insertions(+), 55 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 81b8139..c5a4c1d 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -130,13 +130,13 @@ where #[derive(Debug)] struct CutResult { - before_cut: Option<(Bound, Bound)>, - inside_cut: Option<(Bound, Bound)>, - after_cut: Option<(Bound, Bound)>, + pub before_cut: Option<(Bound, Bound)>, + pub inside_cut: Option<(Bound, Bound)>, + pub after_cut: Option<(Bound, Bound)>, } #[tested] -fn cut_range_bounds<'a, I, B, C>( +pub(crate) fn cut_range_bounds<'a, I, B, C>( base_range_bounds: &'a B, cut_range_bounds: &'a C, ) -> CutResult<&'a I> diff --git a/src/range_bounds_map.rs b/src/range_bounds_map.rs index b585972..0dc50e1 100644 --- a/src/range_bounds_map.rs +++ b/src/range_bounds_map.rs @@ -33,8 +33,8 @@ use serde::{Deserialize, Deserializer, Serialize, Serializer}; use crate::bound_ord::BoundOrd; use crate::helpers::{ - cmp_range_bounds_with_bound_ord, contains_bound_ord, is_valid_range_bounds, - overlaps, + cmp_range_bounds_with_bound_ord, contains_bound_ord, cut_range_bounds, + is_valid_range_bounds, overlaps, }; use crate::TryFromBounds; @@ -666,19 +666,99 @@ where /// assert_eq!(base, after_cut); /// assert!(base.cut(&(60..=80)).is_err()); /// ``` - //#[tested] - //pub fn cut( - //&mut self, - //range_bounds: Q, - //) -> Result< - //impl DoubleEndedIterator, Bound<&I>), V)>, - //TryFromBoundsError, - //> - //where - //Q: RangeBounds + Clone, - //{ - //todo!() - //} + #[tested] + pub fn cut<'a, Q>( + &'a mut self, + range_bounds: Q, + ) -> Result + '_, TryFromBoundsError> + where + Q: 'a + RangeBounds, + I: Clone, + K: TryFromBounds, + V: Clone, + { + // This is so clean and mathematically pleasing omg i'm in love with it + match range_bounds.start_bound() { + Bound::Included(point) => self.bisect_at_point(point, false)?, + Bound::Excluded(point) => self.bisect_at_point(point, true)?, + Bound::Unbounded => {} + } + match range_bounds.end_bound() { + Bound::Included(point) => self.bisect_at_point(point, true)?, + Bound::Excluded(point) => self.bisect_at_point(point, false)?, + Bound::Unbounded => {} + } + + return Ok(self.remove_overlapping(range_bounds)); + } + //does nothing if it hits a degenerate interval or if it would + //leave invalid range_bounds within the structure + fn bisect_at_point( + &mut self, + point: &I, + inclusive_on_left: bool, + ) -> Result<(), TryFromBoundsError> + where + I: Clone, + K: TryFromBounds, + V: Clone, + { + if let Some((start_bound, end_bound)) = + self.get_entry_at_point(point).map(|range_bounds| { + ( + range_bounds.0.start_bound().cloned(), + range_bounds.0.end_bound().cloned(), + ) + }) { + //don't bother doing anything in these situations + match (&start_bound, &end_bound) { + (Bound::Included(start_point), _) if start_point == point => { + if !inclusive_on_left { + return Ok(()); + } + } + (_, Bound::Included(end_point)) if end_point == point => { + if inclusive_on_left { + return Ok(()); + } + } + (Bound::Included(start_point), Bound::Included(end_point)) + if start_point == end_point => + { + return Ok(()); + } + _ => {} + } + + let before_section = K::try_from_bounds( + start_bound, + if inclusive_on_left { + Bound::Included(point.clone()) + } else { + Bound::Excluded(point.clone()) + }, + )?; + let after_section = K::try_from_bounds( + if !inclusive_on_left { + Bound::Included(point.clone()) + } else { + Bound::Excluded(point.clone()) + }, + end_bound, + )?; + + let value = self + .inner + .remove(comp_start(Bound::Included(point))) + .unwrap(); + + self.inner + .insert(before_section, value.clone(), double_comp()); + self.inner.insert(after_section, value, double_comp()); + } + + return Ok(()); + } /// Identical to [`RangeBoundsMap::cut()`] except it returns an /// iterator of `(Result, diff --git a/src/try_from_bounds.rs b/src/try_from_bounds.rs index 842f64a..f699dcc 100644 --- a/src/try_from_bounds.rs +++ b/src/try_from_bounds.rs @@ -24,6 +24,8 @@ use std::ops::{ use labels::{not_a_fn, trivial}; +use crate::TryFromBoundsError; + /// A "newtype" trait to copy [`TryFrom`]. /// /// I am forced to use this "newtype" instead of [`TryFrom`] because @@ -41,24 +43,9 @@ pub trait TryFromBounds { fn try_from_bounds( start_bound: Bound, end_bound: Bound, - ) -> Option + ) -> Result where Self: Sized; - // optimisation: make this non-implemented so the trait impls can - // define them more efficiently - #[not_a_fn] - fn is_valid(range_bounds: &Q) -> bool - where - Q: RangeBounds, - Self: Sized, - I: Clone, - { - Self::try_from_bounds( - range_bounds.start_bound().cloned(), - range_bounds.end_bound().cloned(), - ) - .is_some() - } } impl TryFromBounds for (Bound, Bound) { @@ -66,8 +53,8 @@ impl TryFromBounds for (Bound, Bound) { fn try_from_bounds( start_bound: Bound, end_bound: Bound, - ) -> Option { - Some((start_bound, end_bound)) + ) -> Result { + Ok((start_bound, end_bound)) } } @@ -76,10 +63,10 @@ impl TryFromBounds for Range { fn try_from_bounds( start_bound: Bound, end_bound: Bound, - ) -> Option { + ) -> Result { match (start_bound, end_bound) { - (Bound::Included(start), Bound::Excluded(end)) => Some(start..end), - _ => None, + (Bound::Included(start), Bound::Excluded(end)) => Ok(start..end), + _ => Err(TryFromBoundsError), } } } @@ -89,10 +76,10 @@ impl TryFromBounds for RangeInclusive { fn try_from_bounds( start_bound: Bound, end_bound: Bound, - ) -> Option { + ) -> Result { match (start_bound, end_bound) { - (Bound::Included(start), Bound::Included(end)) => Some(start..=end), - _ => None, + (Bound::Included(start), Bound::Included(end)) => Ok(start..=end), + _ => Err(TryFromBoundsError), } } } @@ -102,10 +89,10 @@ impl TryFromBounds for RangeFrom { fn try_from_bounds( start_bound: Bound, end_bound: Bound, - ) -> Option { + ) -> Result { match (start_bound, end_bound) { - (Bound::Included(start), Bound::Unbounded) => Some(start..), - _ => None, + (Bound::Included(start), Bound::Unbounded) => Ok(start..), + _ => Err(TryFromBoundsError), } } } @@ -115,10 +102,10 @@ impl TryFromBounds for RangeTo { fn try_from_bounds( start_bound: Bound, end_bound: Bound, - ) -> Option { + ) -> Result { match (start_bound, end_bound) { - (Bound::Unbounded, Bound::Excluded(end)) => Some(..end), - _ => None, + (Bound::Unbounded, Bound::Excluded(end)) => Ok(..end), + _ => Err(TryFromBoundsError), } } } @@ -128,10 +115,10 @@ impl TryFromBounds for RangeToInclusive { fn try_from_bounds( start_bound: Bound, end_bound: Bound, - ) -> Option { + ) -> Result { match (start_bound, end_bound) { - (Bound::Unbounded, Bound::Included(end)) => Some(..=end), - _ => None, + (Bound::Unbounded, Bound::Included(end)) => Ok(..=end), + _ => Err(TryFromBoundsError), } } } @@ -141,10 +128,10 @@ impl TryFromBounds for RangeFull { fn try_from_bounds( start_bound: Bound, end_bound: Bound, - ) -> Option { + ) -> Result { match (start_bound, end_bound) { - (Bound::Unbounded, Bound::Unbounded) => Some(..), - _ => None, + (Bound::Unbounded, Bound::Unbounded) => Ok(..), + _ => Err(TryFromBoundsError), } } }