From 6de99232df21adaf9df99dfa6afe48955ba49fe9 Mon Sep 17 00:00:00 2001 From: ripytide Date: Wed, 27 Dec 2023 13:26:50 +0000 Subject: [PATCH 1/4] extracted the InclusiveInterval into a separate module --- README.md | 4 +- src/discrete_range_map.rs | 91 ++++++------------- src/{test_ranges.rs => inclusive_interval.rs} | 44 ++++++++- src/lib.rs | 11 ++- 4 files changed, 77 insertions(+), 73 deletions(-) rename src/{test_ranges.rs => inclusive_interval.rs} (67%) diff --git a/README.md b/README.md index f7cf4c4..67b79f0 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ for some methods so if in doubt check a methods trait bounds. ## Example using an Inclusive-Exclusive range ```rust -use discrete_range_map::test_ranges::ie; +use discrete_range_map::inclusive_interval::ie; use discrete_range_map::DiscreteRangeMap; let mut map = DiscreteRangeMap::new(); @@ -45,7 +45,7 @@ assert_eq!(map.contains_point(5), true); ```rust use std::ops::{Bound, RangeBounds}; -use discrete_range_map::test_ranges::ie; +use discrete_range_map::inclusive_interval::ie; use discrete_range_map::{ DiscreteFinite, DiscreteRangeMap, InclusiveInterval, InclusiveRange, diff --git a/src/discrete_range_map.rs b/src/discrete_range_map.rs index ed55985..a2d1c53 100644 --- a/src/discrete_range_map.rs +++ b/src/discrete_range_map.rs @@ -24,7 +24,6 @@ use core::cmp::Ordering; use core::fmt::{self, Debug}; use core::iter::once; use core::marker::PhantomData; -use core::ops::{Bound, RangeBounds}; use btree_monstrousity::btree_map::{ IntoIter as BTreeMapIntoIter, SearchBoundCustom, @@ -37,7 +36,7 @@ use serde::ser::SerializeSeq; use serde::{Deserialize, Deserializer, Serialize, Serializer}; use crate::utils::{cmp_point_with_range, cut_range, is_valid_range, overlaps}; -use crate::DiscreteFinite; +use crate::{DiscreteFinite, InclusiveInterval}; /// An ordered map of non-overlapping ranges based on [`BTreeMap`]. /// @@ -54,7 +53,7 @@ use crate::DiscreteFinite; /// /// # Examples /// ``` -/// use discrete_range_map::test_ranges::ie; +/// use discrete_range_map::inclusive_interval::ie; /// use discrete_range_map::DiscreteRangeMap; /// /// // Make a map of ranges to booleans @@ -93,40 +92,6 @@ pub struct OverlapError { pub value: V, } -/// A compatibility type used in [`RangeType`] for allowing the library to -/// create the custom K type used in the map when necessary. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)] -pub struct InclusiveInterval { - /// The start of the interval, inclusive. - pub start: I, - /// The end of the interval, inclusive. - pub end: I, -} -impl RangeBounds for InclusiveInterval -where - I: PointType, -{ - fn start_bound(&self) -> Bound<&I> { - Bound::Included(&self.start) - } - - fn end_bound(&self) -> Bound<&I> { - Bound::Included(&self.end) - } -} -impl InclusiveRange for InclusiveInterval -where - I: PointType, -{ - fn start(&self) -> I { - self.start - } - - fn end(&self) -> I { - self.end - } -} - /// The marker trait for valid point types, a blanket implementation is provided for all types /// which implement this traits' super-traits so you shouln't need to implement this yourself. pub trait PointType: Ord + Copy + DiscreteFinite {} @@ -161,7 +126,7 @@ where /// /// # Examples /// ``` - /// use discrete_range_map::test_ranges::{ie, ii}; + /// use discrete_range_map::inclusive_interval::{ie, ii}; /// use discrete_range_map::DiscreteRangeMap; /// /// let mut map = DiscreteRangeMap::new(); @@ -194,7 +159,7 @@ where /// /// # Examples /// ``` - /// use discrete_range_map::test_ranges::ie; + /// use discrete_range_map::inclusive_interval::ie; /// use discrete_range_map::DiscreteRangeMap; /// /// let map = DiscreteRangeMap::from_slice_strict([ @@ -241,7 +206,7 @@ where /// /// # Examples /// ``` - /// use discrete_range_map::test_ranges::ie; + /// use discrete_range_map::inclusive_interval::ie; /// use discrete_range_map::DiscreteRangeMap; /// /// let mut map = DiscreteRangeMap::from_slice_strict([ @@ -283,7 +248,7 @@ where /// /// # Examples /// ``` - /// use discrete_range_map::test_ranges::ie; + /// use discrete_range_map::inclusive_interval::ie; /// use discrete_range_map::DiscreteRangeMap; /// /// let map = DiscreteRangeMap::from_slice_strict([ @@ -306,7 +271,7 @@ where /// /// # Examples /// ``` - /// use discrete_range_map::test_ranges::ie; + /// use discrete_range_map::inclusive_interval::ie; /// use discrete_range_map::DiscreteRangeMap; /// let mut map = /// DiscreteRangeMap::from_slice_strict([(ie(1, 4), false)]) @@ -327,7 +292,7 @@ where /// /// # Examples /// ``` - /// use discrete_range_map::test_ranges::ie; + /// use discrete_range_map::inclusive_interval::ie; /// use discrete_range_map::DiscreteRangeMap; /// /// let map = DiscreteRangeMap::from_slice_strict([ @@ -353,7 +318,7 @@ where /// /// # Examples /// ``` - /// use discrete_range_map::test_ranges::{ie, iu}; + /// use discrete_range_map::inclusive_interval::{ie, iu}; /// use discrete_range_map::DiscreteRangeMap; /// /// let map = DiscreteRangeMap::from_slice_strict([ @@ -402,7 +367,7 @@ where /// /// # Examples /// ``` - /// use discrete_range_map::test_ranges::ie; + /// use discrete_range_map::inclusive_interval::ie; /// use discrete_range_map::DiscreteRangeMap; /// /// let mut map = DiscreteRangeMap::from_slice_strict([ @@ -466,7 +431,7 @@ where /// /// # Examples /// ``` - /// use discrete_range_map::test_ranges::{ie, ii}; + /// use discrete_range_map::inclusive_interval::{ie, ii}; /// use discrete_range_map::DiscreteRangeMap; /// /// let mut base = DiscreteRangeMap::from_slice_strict([ @@ -633,7 +598,7 @@ where /// /// # Examples /// ``` - /// use discrete_range_map::test_ranges::{ie, iu}; + /// use discrete_range_map::inclusive_interval::{ie, iu}; /// use discrete_range_map::DiscreteRangeMap; /// /// let map = DiscreteRangeMap::from_slice_strict([ @@ -727,7 +692,7 @@ where /// /// # Examples /// ``` - /// use discrete_range_map::test_ranges::ie; + /// use discrete_range_map::inclusive_interval::ie; /// use discrete_range_map::DiscreteRangeMap; /// /// let map = DiscreteRangeMap::from_slice_strict([ @@ -765,7 +730,7 @@ where /// /// # Examples /// ``` - /// use discrete_range_map::test_ranges::ie; + /// use discrete_range_map::inclusive_interval::ie; /// use discrete_range_map::{DiscreteRangeMap, OverlapError}; /// /// let mut map = DiscreteRangeMap::new(); @@ -865,7 +830,7 @@ where /// /// # Examples /// ``` - /// use discrete_range_map::test_ranges::ie; + /// use discrete_range_map::inclusive_interval::ie; /// use discrete_range_map::{DiscreteRangeMap, OverlapError}; /// /// let mut map = DiscreteRangeMap::from_slice_strict([ @@ -953,7 +918,7 @@ where /// /// # Examples /// ``` - /// use discrete_range_map::test_ranges::ie; + /// use discrete_range_map::inclusive_interval::ie; /// use discrete_range_map::{DiscreteRangeMap, OverlapError}; /// /// let mut map = DiscreteRangeMap::from_slice_strict([ @@ -1054,7 +1019,7 @@ where /// /// # Examples /// ``` - /// use discrete_range_map::test_ranges::ie; + /// use discrete_range_map::inclusive_interval::ie; /// use discrete_range_map::{DiscreteRangeMap, OverlapError}; /// /// let mut map = DiscreteRangeMap::from_slice_strict([ @@ -1127,7 +1092,7 @@ where /// /// # Examples /// ``` - /// use discrete_range_map::test_ranges::ie; + /// use discrete_range_map::inclusive_interval::ie; /// use discrete_range_map::{DiscreteRangeMap, OverlapError}; /// /// let mut map = DiscreteRangeMap::from_slice_strict([ @@ -1215,7 +1180,7 @@ where /// /// # Examples /// ``` - /// use discrete_range_map::test_ranges::ie; + /// use discrete_range_map::inclusive_interval::ie; /// use discrete_range_map::DiscreteRangeMap; /// /// let mut map = @@ -1254,7 +1219,7 @@ where /// /// # Examples /// ``` - /// use discrete_range_map::test_ranges::ie; + /// use discrete_range_map::inclusive_interval::ie; /// use discrete_range_map::DiscreteRangeMap; /// /// let map = DiscreteRangeMap::from_slice_strict([ @@ -1288,7 +1253,7 @@ where /// /// # Examples /// ``` - /// use discrete_range_map::test_ranges::ie; + /// use discrete_range_map::inclusive_interval::ie; /// use discrete_range_map::DiscreteRangeMap; /// /// let slice = @@ -1332,7 +1297,7 @@ impl DiscreteRangeMap { /// /// # Examples /// ``` - /// use discrete_range_map::test_ranges::ie; + /// use discrete_range_map::inclusive_interval::ie; /// use discrete_range_map::DiscreteRangeMap; /// /// let mut map = DiscreteRangeMap::new(); @@ -1350,7 +1315,7 @@ impl DiscreteRangeMap { /// /// # Examples /// ``` - /// use discrete_range_map::test_ranges::ie; + /// use discrete_range_map::inclusive_interval::ie; /// use discrete_range_map::DiscreteRangeMap; /// /// let mut map = DiscreteRangeMap::new(); @@ -1368,7 +1333,7 @@ impl DiscreteRangeMap { /// /// # Examples /// ``` - /// use discrete_range_map::test_ranges::ie; + /// use discrete_range_map::inclusive_interval::ie; /// use discrete_range_map::DiscreteRangeMap; /// /// let map = DiscreteRangeMap::from_slice_strict([ @@ -1394,7 +1359,7 @@ impl DiscreteRangeMap { /// /// # Examples /// ``` - /// use discrete_range_map::test_ranges::ie; + /// use discrete_range_map::inclusive_interval::ie; /// use discrete_range_map::DiscreteRangeMap; /// /// let mut map = DiscreteRangeMap::from_slice_strict([ @@ -1422,7 +1387,7 @@ impl DiscreteRangeMap { /// /// # Examples /// ``` - /// use discrete_range_map::test_ranges::ie; + /// use discrete_range_map::inclusive_interval::ie; /// use discrete_range_map::DiscreteRangeMap; /// /// let map = DiscreteRangeMap::from_slice_strict([ @@ -1443,7 +1408,7 @@ impl DiscreteRangeMap { /// # Examples /// ``` /// use discrete_range_map::DiscreteRangeMap; - /// use discrete_range_map::test_ranges::ie; + /// use discrete_range_map::inclusive_interval::ie; /// /// let map = DiscreteRangeMap::from_slice_strict([ /// (ie(1, 4), false), @@ -1713,7 +1678,7 @@ mod tests { use pretty_assertions::assert_eq; use super::*; - use crate::test_ranges::{ee, ei, ie, ii, iu, ue, ui, uu}; + use crate::inclusive_interval::{ee, ei, ie, ii, iu, ue, ui, uu}; use crate::utils::{config, contains_point, Config, CutResult}; //only every other number to allow mathematical_overlapping_definition diff --git a/src/test_ranges.rs b/src/inclusive_interval.rs similarity index 67% rename from src/test_ranges.rs rename to src/inclusive_interval.rs index fa85bbc..83ce0e8 100644 --- a/src/test_ranges.rs +++ b/src/inclusive_interval.rs @@ -17,10 +17,48 @@ You should have received a copy of the GNU Affero General Public License along with discrete_range_map. If not, see . */ -//! A collection of helper functions for making [`InclusiveInterval`]s from `i8`'s used for testing -//! and example purposes. +//! A module containing [`InclusiveInterval`] and it's various constructor functions. -use crate::{DiscreteFinite, InclusiveInterval}; +use core::ops::{RangeBounds, Bound}; + +use serde::{Serialize, Deserialize}; + +use crate::{DiscreteFinite, PointType, InclusiveRange}; + +/// The interval type used throughout this crate both for the examples and +/// for use by library users if they don't wish to create their own +/// interval types. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)] +pub struct InclusiveInterval { + /// The start of the interval, inclusive. + pub start: I, + /// The end of the interval, inclusive. + pub end: I, +} +impl RangeBounds for InclusiveInterval +where + I: PointType, +{ + fn start_bound(&self) -> Bound<&I> { + Bound::Included(&self.start) + } + + fn end_bound(&self) -> Bound<&I> { + Bound::Included(&self.end) + } +} +impl InclusiveRange for InclusiveInterval +where + I: PointType, +{ + fn start(&self) -> I { + self.start + } + + fn end(&self) -> I { + self.end + } +} /// An unbounded-unbounded interval pub fn uu() -> InclusiveInterval { diff --git a/src/lib.rs b/src/lib.rs index 1a54f39..79290a1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -35,7 +35,7 @@ along with discrete_range_map. If not, see . //! ## Example using an Inclusive-Exclusive range //! //! ```rust -//! use discrete_range_map::test_ranges::ie; +//! use discrete_range_map::inclusive_interval::ie; //! use discrete_range_map::DiscreteRangeMap; //! //! let mut map = DiscreteRangeMap::new(); @@ -53,7 +53,7 @@ along with discrete_range_map. If not, see . //! ```rust //! use std::ops::{Bound, RangeBounds}; //! -//! use discrete_range_map::test_ranges::ie; +//! use discrete_range_map::inclusive_interval::ie; //! use discrete_range_map::{ //! DiscreteFinite, DiscreteRangeMap, InclusiveInterval, //! InclusiveRange, @@ -384,11 +384,12 @@ pub(crate) mod utils; pub mod discrete_finite; pub mod discrete_range_map; pub mod discrete_range_set; -pub mod test_ranges; +pub mod inclusive_interval; pub use crate::discrete_finite::DiscreteFinite; pub use crate::discrete_range_map::{ - DiscreteRangeMap, InclusiveInterval, InclusiveRange, OverlapError, - PointType, RangeType, + DiscreteRangeMap, InclusiveRange, OverlapError, PointType, RangeType, }; pub use crate::discrete_range_set::DiscreteRangeSet; +pub use crate::inclusive_interval::InclusiveInterval; + From 3616225c13541ffa0c8f3db9cf3014886cf245a0 Mon Sep 17 00:00:00 2001 From: ripytide Date: Wed, 27 Dec 2023 14:47:06 +0000 Subject: [PATCH 2/4] made `InclusiveInterval` validity a construction time invariant --- README.md | 4 + src/discrete_range_map.rs | 24 +-- src/discrete_range_set.rs | 10 +- src/inclusive_interval.rs | 355 ++++++++++++++++++++++++++++++++------ src/lib.rs | 22 ++- src/utils.rs | 16 +- 6 files changed, 341 insertions(+), 90 deletions(-) diff --git a/README.md b/README.md index 67b79f0..4e40cae 100644 --- a/README.md +++ b/README.md @@ -127,6 +127,10 @@ differ depending on whether the underlying type is `Discrete` or `Discrete` but `5.0..=6.0` does **not** touch `7.0..=8.0` since the value `6.5` exists. +Importantly, this also makes Inclusive/Exclusive ended ranges really +easy to work with as they can be losslessly converted between one +another. For example, `3..6` is equivalent to `3..=5`. + ### Finite-ness At the moment this crate is also designed to work only with [`Finite`] diff --git a/src/discrete_range_map.rs b/src/discrete_range_map.rs index a2d1c53..f70ee48 100644 --- a/src/discrete_range_map.rs +++ b/src/discrete_range_map.rs @@ -17,7 +17,7 @@ You should have received a copy of the GNU Affero General Public License along with discrete_range_map. If not, see . */ -//! The module containing [`DiscreteRangeMap`] and related types. +//! A module containing [`DiscreteRangeMap`] and related types. use alloc::vec::Vec; use core::cmp::Ordering; @@ -35,7 +35,7 @@ use serde::de::{SeqAccess, Visitor}; use serde::ser::SerializeSeq; use serde::{Deserialize, Deserializer, Serialize, Serializer}; -use crate::utils::{cmp_point_with_range, cut_range, is_valid_range, overlaps}; +use crate::utils::{cmp_point_with_range, cut_range, overlaps}; use crate::{DiscreteFinite, InclusiveInterval}; /// An ordered map of non-overlapping ranges based on [`BTreeMap`]. @@ -671,7 +671,7 @@ where end: second.0.down().unwrap(), }) }) - .filter(|range| is_valid_range(*range)); + .filter(|range| range.is_valid()); //possibly add the trimmed start and end gaps return trimmed_start_gap @@ -1261,7 +1261,7 @@ where /// /// let map: DiscreteRangeMap<_, _, _> = /// DiscreteRangeMap::from_iter_strict( - /// slice.into_iter().filter(|(range, _)| range.start > 2), + /// slice.into_iter().filter(|(range, _)| range.start() > 2), /// ) /// .unwrap(); /// ``` @@ -1428,12 +1428,12 @@ impl DiscreteRangeMap { // Helper Functions ========================== -fn invalid_range_panic(range: Q) +pub(crate) fn invalid_range_panic(range: Q) where I: PointType, Q: RangeType, { - if !is_valid_range(range) { + if !range.is_valid() { panic!( "invalid range given to function see here for more details: https://docs.rs/discrete_range_map/latest/discrete_range_map/#invalid-ranges" ); @@ -2304,24 +2304,24 @@ mod tests { 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)); + assert!(x.is_valid()); } if let Some(x) = result.inside_cut { - assert!(is_valid_range(x)); + assert!(x.is_valid()); } if let Some(x) = result.after_cut { - assert!(is_valid_range(x)); + assert!(x.is_valid()); } let result = cut_range(ie(3, 8), ie(3, 5)); if let Some(x) = result.before_cut { - assert!(is_valid_range(x)); + assert!(x.is_valid()); } if let Some(x) = result.inside_cut { - assert!(is_valid_range(x)); + assert!(x.is_valid()); } if let Some(x) = result.after_cut { - assert!(is_valid_range(x)); + assert!(x.is_valid()); } } diff --git a/src/discrete_range_set.rs b/src/discrete_range_set.rs index 0cfd8a4..0a9a618 100644 --- a/src/discrete_range_set.rs +++ b/src/discrete_range_set.rs @@ -17,10 +17,12 @@ You should have received a copy of the GNU Affero General Public License along with discrete_range_map. If not, see . */ -//! The module containing [`DiscreteRangeSet`] and related types. Since -//! [`DiscreteRangeSet`] is just a wrapper around [`DiscreteRangeMap`], most of -//! the methods' docs will point towards the equivalent method's docs on -//! [`DiscreteRangeMap`] to prevent inconsistency. +//! A module containing [`DiscreteRangeSet`] and related types. +//! +//! Since [`DiscreteRangeSet`] is just a wrapper around +//! [`DiscreteRangeMap`], most of the methods' docs will point towards the +//! equivalent method's docs on [`DiscreteRangeMap`] to prevent +//! inconsistency. use core::fmt; use core::marker::PhantomData; diff --git a/src/inclusive_interval.rs b/src/inclusive_interval.rs index 83ce0e8..c9d4530 100644 --- a/src/inclusive_interval.rs +++ b/src/inclusive_interval.rs @@ -17,24 +17,80 @@ You should have received a copy of the GNU Affero General Public License along with discrete_range_map. If not, see . */ -//! A module containing [`InclusiveInterval`] and it's various constructor functions. +//! A module containing [`InclusiveInterval`] and its constructors. +//! +//! The constructors are not associated functions as then you must write +//! `InclusiveInterval` before it every time you want create an interval +//! which is a bit annoying as you can't import associated function in rust +//! yet. If you would still like the associated versions I would be happy to +//! add them as well, just open a PR/Issue. -use core::ops::{RangeBounds, Bound}; +use core::ops::{Bound, RangeBounds}; -use serde::{Serialize, Deserialize}; +use serde::{Deserialize, Serialize}; -use crate::{DiscreteFinite, PointType, InclusiveRange}; +use crate::discrete_range_map::invalid_range_panic; +use crate::{InclusiveRange, PointType}; -/// The interval type used throughout this crate both for the examples and -/// for use by library users if they don't wish to create their own -/// interval types. +/// An inclusive interval, only valid intervals can be constructed. +/// +/// This interval struct is used throughout this crate for the examples and +/// tests but can also be used by library users if they don't wish to create +/// their own interval types. +/// +/// To create an `InclusiveInterval` use one of the various contrutor +/// functions which will all panic if you try to create an invalid range. +/// See [`Invalid +/// Ranges`](https://docs.rs/discrete_range_map/latest/discrete_range_map/index.html#invalid-ranges) +/// for more details. +/// +/// ``` +/// use discrete_range_map::inclusive_interval::{ee, ii}; +/// +/// let inclusive_interval = ii(4, 4); +/// let exclusive_interval = ee(3, 5); +/// +/// assert_eq!(inclusive_interval, exclusive_interval); +/// ``` +/// +/// ```should_panic +/// use discrete_range_map::inclusive_interval::ee; +/// +/// let invalid_interval = ee(4, 4); +/// ``` #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)] pub struct InclusiveInterval { /// The start of the interval, inclusive. - pub start: I, + pub(crate) start: I, /// The end of the interval, inclusive. - pub end: I, + pub(crate) end: I, } +impl InclusiveInterval +where + I: PointType, +{ + /// The start of the range, inclusive. + /// + /// ``` + /// use discrete_range_map::inclusive_interval::ii; + /// + /// assert_eq!(ii(2, 4).start(), 2); + /// ``` + pub fn start(&self) -> I { + self.start + } + /// The end of the range, inclusive. + /// + /// ``` + /// use discrete_range_map::inclusive_interval::ii; + /// + /// assert_eq!(ii(2, 4).end(), 4); + /// ``` + pub fn end(&self) -> I { + self.end + } +} + impl RangeBounds for InclusiveInterval where I: PointType, @@ -60,63 +116,262 @@ where } } -/// An unbounded-unbounded interval -pub fn uu() -> InclusiveInterval { - InclusiveInterval { - start: i8::MIN, - end: i8::MAX, - } +/// Create an new Unbounded-Unbounded interval. +/// +/// # Panics +/// +/// Panics if the range is an invalid range. See [`Invalid +/// Ranges`](https://docs.rs/discrete_range_map/latest/discrete_range_map/index.html#invalid-ranges) +/// for more details. +/// +/// ``` +/// use discrete_range_map::inclusive_interval::uu; +/// use discrete_range_map::InclusiveInterval; +/// +/// let interval1: InclusiveInterval = uu(); +/// let interval2: InclusiveInterval = uu(); +/// +/// assert_eq!(interval1, interval2) +/// ``` +pub fn uu() -> InclusiveInterval +where + I: PointType, +{ + let interval = InclusiveInterval { + start: I::MIN, + end: I::MAX, + }; + + invalid_range_panic(interval); + + interval } -/// An unbounded-included interval -pub fn ui(x: i8) -> InclusiveInterval { - InclusiveInterval { - start: i8::MIN, +/// Create an new Unbounded-Included interval. +/// +/// # Panics +/// +/// Panics if the range is an invalid range. See [`Invalid +/// Ranges`](https://docs.rs/discrete_range_map/latest/discrete_range_map/index.html#invalid-ranges) +/// for more details. +/// +/// ``` +/// use discrete_range_map::inclusive_interval::ui; +/// +/// let interval1 = ui(1); +/// let interval2 = ui(4); +/// +/// assert_ne!(interval1, interval2) +/// ``` +pub fn ui(x: I) -> InclusiveInterval +where + I: PointType, +{ + let interval = InclusiveInterval { + start: I::MIN, end: x, - } + }; + + invalid_range_panic(interval); + + interval } -/// An unbounded-excluded interval -pub fn ue(x: i8) -> InclusiveInterval { - InclusiveInterval { - start: i8::MIN, +/// Create an new Unbounded-Excluded interval. +/// +/// # Panics +/// +/// Panics if the range is an invalid range. See [`Invalid +/// Ranges`](https://docs.rs/discrete_range_map/latest/discrete_range_map/index.html#invalid-ranges) +/// for more details. +/// +/// ``` +/// use discrete_range_map::inclusive_interval::ue; +/// +/// let interval1 = ue(1); +/// let interval2 = ue(4); +/// +/// assert_ne!(interval1, interval2) +/// ``` +pub fn ue(x: I) -> InclusiveInterval +where + I: PointType, +{ + let interval = InclusiveInterval { + start: I::MIN, end: x.down().unwrap(), - } + }; + + invalid_range_panic(interval); + + interval } -/// An included-unbounded interval -pub fn iu(x: i8) -> InclusiveInterval { - InclusiveInterval { +/// Create an new Included-Unbounded interval. +/// +/// # Panics +/// +/// Panics if the range is an invalid range. See [`Invalid +/// Ranges`](https://docs.rs/discrete_range_map/latest/discrete_range_map/index.html#invalid-ranges) +/// for more details. +/// +/// ``` +/// use discrete_range_map::inclusive_interval::iu; +/// +/// let interval1 = iu(1); +/// let interval2 = iu(4); +/// +/// assert_ne!(interval1, interval2) +/// ``` +pub fn iu(x: I) -> InclusiveInterval +where + I: PointType, +{ + let interval = InclusiveInterval { start: x, - end: i8::MAX, - } + end: I::MAX, + }; + + invalid_range_panic(interval); + + interval } -/// An excluded-unbounded interval -pub fn eu(x: i8) -> InclusiveInterval { - InclusiveInterval { +/// Create an new Excluded-Unbounded interval. +/// +/// # Panics +/// +/// Panics if the range is an invalid range. See [`Invalid +/// Ranges`](https://docs.rs/discrete_range_map/latest/discrete_range_map/index.html#invalid-ranges) +/// for more details. +/// +/// ``` +/// use discrete_range_map::inclusive_interval::eu; +/// +/// let interval1 = eu(1); +/// let interval2 = eu(4); +/// +/// assert_ne!(interval1, interval2) +/// ``` +pub fn eu(x: I) -> InclusiveInterval +where + I: PointType, +{ + let interval = InclusiveInterval { start: x.up().unwrap(), - end: i8::MAX, - } + end: I::MAX, + }; + + invalid_range_panic(interval); + + interval } -/// An included-included interval -pub fn ii(x1: i8, x2: i8) -> InclusiveInterval { - InclusiveInterval { start: x1, end: x2 } +/// Create an new Included-Included interval. +/// +/// # Panics +/// +/// Panics if the range is an invalid range. See [`Invalid +/// Ranges`](https://docs.rs/discrete_range_map/latest/discrete_range_map/index.html#invalid-ranges) +/// for more details. +/// +/// ``` +/// use discrete_range_map::inclusive_interval::ii; +/// +/// let interval1 = ii(0, 4); +/// let interval2 = ii(2, 6); +/// +/// assert_ne!(interval1, interval2) +/// ``` +pub fn ii(x1: I, x2: I) -> InclusiveInterval +where + I: PointType, +{ + let interval = InclusiveInterval { start: x1, end: x2 }; + + invalid_range_panic(interval); + + interval } -/// An included-excluded interval -pub fn ie(x1: i8, x2: i8) -> InclusiveInterval { - InclusiveInterval { +/// Create an new Included-Excluded interval. +/// +/// # Panics +/// +/// Panics if the range is an invalid range. See [`Invalid +/// Ranges`](https://docs.rs/discrete_range_map/latest/discrete_range_map/index.html#invalid-ranges) +/// for more details. +/// +/// ``` +/// use discrete_range_map::inclusive_interval::ie; +/// +/// let interval1 = ie(0, 4); +/// let interval2 = ie(2, 6); +/// +/// assert_ne!(interval1, interval2) +/// ``` +pub fn ie(x1: I, x2: I) -> InclusiveInterval +where + I: PointType, +{ + let interval = InclusiveInterval { start: x1, end: x2.down().unwrap(), - } + }; + + invalid_range_panic(interval); + + interval } -/// An excluded-included interval -pub fn ei(x1: i8, x2: i8) -> InclusiveInterval { - InclusiveInterval { +/// Create an new Excluded-Included interval. +/// +/// # Panics +/// +/// Panics if the range is an invalid range. See [`Invalid +/// Ranges`](https://docs.rs/discrete_range_map/latest/discrete_range_map/index.html#invalid-ranges) +/// for more details. +/// +/// ``` +/// use discrete_range_map::inclusive_interval::ei; +/// +/// let interval1 = ei(0, 4); +/// let interval2 = ei(2, 6); +/// +/// assert_ne!(interval1, interval2) +/// ``` +pub fn ei(x1: I, x2: I) -> InclusiveInterval +where + I: PointType, +{ + let interval = InclusiveInterval { start: x1.up().unwrap(), end: x2, - } + }; + + invalid_range_panic(interval); + + interval } -/// An excluded-excluded interval -pub fn ee(x1: i8, x2: i8) -> InclusiveInterval { - InclusiveInterval { +/// Create an new Excluded-Excluded interval. +/// +/// # Panics +/// +/// Panics if the range is an invalid range. See [`Invalid +/// Ranges`](https://docs.rs/discrete_range_map/latest/discrete_range_map/index.html#invalid-ranges) +/// for more details. +/// +/// ``` +/// use discrete_range_map::inclusive_interval::ee; +/// +/// let interval1 = ee(0, 4); +/// let interval2 = ee(2, 6); +/// +/// assert_ne!(interval1, interval2) +/// ``` +pub fn ee(x1: I, x2: I) -> InclusiveInterval +where + I: PointType, +{ + let interval = InclusiveInterval { start: x1.up().unwrap(), end: x2.down().unwrap(), - } + }; + + invalid_range_panic(interval); + + interval } diff --git a/src/lib.rs b/src/lib.rs index 79290a1..a18d487 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -86,12 +86,12 @@ along with discrete_range_map. If not, see . //! // Second, we need to implement From> //! impl From> for Reservation { //! fn from(value: InclusiveInterval) -> Self { -//! if value.end == i8::MAX { -//! Reservation::Infinite(value.start) +//! if value.end() == i8::MAX { +//! Reservation::Infinite(value.start()) //! } else { //! Reservation::Finite( -//! value.start, -//! value.end.up().unwrap(), +//! value.start(), +//! value.end().up().unwrap(), //! ) //! } //! } @@ -135,6 +135,10 @@ along with discrete_range_map. If not, see . //! `Discrete` but `5.0..=6.0` does **not** touch `7.0..=8.0` since the //! value `6.5` exists. //! +//! Importantly, this also makes Inclusive/Exclusive ended ranges really +//! easy to work with as they can be losslessly converted between one +//! another. For example, `3..6` is equivalent to `3..=5`. +//! //! ### Finite-ness //! //! At the moment this crate is also designed to work only with [`Finite`] @@ -231,6 +235,7 @@ along with discrete_range_map. If not, see . //! // Infinity is encountered such as when it might be //! // returned by `get_entry_at_point()`, for example: //! +//! use discrete_range_map::inclusive_interval::uu; //! use discrete_range_map::{DiscreteRangeMap, InclusiveInterval}; //! //! let map: DiscreteRangeMap< @@ -241,13 +246,7 @@ along with discrete_range_map. If not, see . //! //! let mut gap = map.get_entry_at_point(WithInfinity::Finite(4)); //! -//! assert_eq!( -//! gap, -//! Err(InclusiveInterval { -//! start: WithInfinity::Finite(0), -//! end: WithInfinity::Infinity, -//! }) -//! ); +//! assert_eq!(gap, Err(uu())); //! ``` //! //! ### Invalid Ranges @@ -392,4 +391,3 @@ pub use crate::discrete_range_map::{ }; pub use crate::discrete_range_set::DiscreteRangeSet; pub use crate::inclusive_interval::InclusiveInterval; - diff --git a/src/utils.rs b/src/utils.rs index 11bcbef..dec4e32 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -19,7 +19,7 @@ along with discrete_range_map. If not, see . use core::cmp::Ordering; -use crate::{InclusiveInterval, PointType, RangeType}; +use crate::{InclusiveInterval, PointType, RangeType, InclusiveRange}; pub(crate) fn cmp_point_with_range(point: I, range: K) -> Ordering where @@ -190,20 +190,12 @@ where //only return valid ranges return CutResult { - before_cut: result.before_cut.filter(|x| is_valid_range(*x)), - inside_cut: result.inside_cut.filter(|x| is_valid_range(*x)), - after_cut: result.after_cut.filter(|x| is_valid_range(*x)), + before_cut: result.before_cut.filter(|x| x.is_valid()), + inside_cut: result.inside_cut.filter(|x| x.is_valid()), + after_cut: result.after_cut.filter(|x| x.is_valid()), }; } -pub(crate) fn is_valid_range(range: K) -> bool -where - I: PointType, - K: RangeType, -{ - range.start() <= range.end() -} - pub(crate) fn overlaps(a: A, b: B) -> bool where I: PointType, From 92850de342b6902c1b123b3b03dbbbacf7b6639a Mon Sep 17 00:00:00 2001 From: ripytide Date: Wed, 27 Dec 2023 14:54:54 +0000 Subject: [PATCH 3/4] add an example to the readme for overlap --- README.md | 3 ++- src/lib.rs | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 4e40cae..c1588e0 100644 --- a/README.md +++ b/README.md @@ -272,7 +272,8 @@ Here are a few examples of ranges and whether they are valid: ### Overlap Two ranges are "overlapping" if there exists a point that is contained -within both ranges. +within both ranges. For example, `2..4` and `2..6` overlap but `2..4` +and `4..8` do not. ### Touching diff --git a/src/lib.rs b/src/lib.rs index a18d487..f0bc278 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -275,7 +275,8 @@ along with discrete_range_map. If not, see . //! ### Overlap //! //! Two ranges are "overlapping" if there exists a point that is contained -//! within both ranges. +//! within both ranges. For example, `2..4` and `2..6` overlap but `2..4` +//! and `4..8` do not. //! //! ### Touching //! From 90f04748b72fcb5be2573823346de62e064135cf Mon Sep 17 00:00:00 2001 From: ripytide Date: Wed, 27 Dec 2023 15:04:35 +0000 Subject: [PATCH 4/4] adde conversion from the `std` `Range` and `RangeInclusive` --- src/inclusive_interval.rs | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/src/inclusive_interval.rs b/src/inclusive_interval.rs index c9d4530..ab6458b 100644 --- a/src/inclusive_interval.rs +++ b/src/inclusive_interval.rs @@ -25,7 +25,7 @@ along with discrete_range_map. If not, see . //! yet. If you would still like the associated versions I would be happy to //! add them as well, just open a PR/Issue. -use core::ops::{Bound, RangeBounds}; +use core::ops::{Bound, Range, RangeBounds, RangeInclusive}; use serde::{Deserialize, Serialize}; @@ -115,6 +115,35 @@ where self.end } } +impl From> for RangeInclusive { + fn from(value: InclusiveInterval) -> Self { + value.start..=value.end + } +} +impl From> for InclusiveInterval +where + I: PointType, +{ + fn from(value: RangeInclusive) -> Self { + ii(*value.start(), *value.end()) + } +} +impl From> for Range +where + I: PointType, +{ + fn from(value: InclusiveInterval) -> Self { + value.start..value.end.up().unwrap() + } +} +impl From> for InclusiveInterval +where + I: PointType, +{ + fn from(value: Range) -> Self { + ie(value.start, value.end) + } +} /// Create an new Unbounded-Unbounded interval. ///