diff --git a/Cargo.lock b/Cargo.lock
index 254a6c9..36220c9 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -2,15 +2,40 @@
# It is not intended for manual editing.
version = 3
+[[package]]
+name = "autocfg"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
+
[[package]]
name = "either"
version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797"
+[[package]]
+name = "num-traits"
+version = "0.2.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd"
+dependencies = [
+ "autocfg",
+]
+
+[[package]]
+name = "ordered-float"
+version = "3.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d84eb1409416d254e4a9c8fa56cc24701755025b458f0fcd8e59e1f5f40c23bf"
+dependencies = [
+ "num-traits",
+]
+
[[package]]
name = "range_bounds_map"
version = "0.0.1"
dependencies = [
"either",
+ "ordered-float",
]
diff --git a/Cargo.toml b/Cargo.toml
index a1b4627..4bf5748 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -7,3 +7,6 @@ edition = "2021"
[dependencies]
either = "1.8.0"
+
+[dev-dependencies]
+ordered-float = "3.4.0"
diff --git a/README.md b/README.md
index b7b7e0f..225697d 100644
--- a/README.md
+++ b/README.md
@@ -25,6 +25,8 @@
- turn overlaps back into a trait to make it public, mabye
+- review caveats again
+
- run cargo fmt
- run and fix cargo clippy
- take a look around idiomatic rust for a bit first
diff --git a/src/bounds.rs b/src/bounds.rs
index 444bedb..0ffcec5 100644
--- a/src/bounds.rs
+++ b/src/bounds.rs
@@ -20,20 +20,44 @@ along with range_bounds_map. If not, see .
use std::cmp::Ordering;
use std::ops::Bound;
+/// An Ord newtype of [`Bound`] specific to [`start_bound()`].
+///
+/// This type is used to circumvent [`BTreeMap`]s (and rust collections
+/// in general) lack of methods for searching with custom
+/// [`comparator`] functions and/or it's lack of a [`Cursor`]-like
+/// API
+///
+/// [`start_bound()`]: https://doc.rust-lang.org/std/ops/trait.RangeBounds.html#tymethod.start_bound
+/// [`BTreeMap`]: https://doc.rust-lang.org/std/collections/struct.BTreeMap.html
+/// [`comparator`]: https://stackoverflow.com/q/34028324
+/// [`Cursor`]: https://github.com/rust-lang/rfcs/issues/1778
#[derive(PartialEq, Debug)]
pub(crate) enum StartBound {
+ /// Mirror of [`Bound::Included`]
Included(T),
+ /// Mirror of [`Bound::Excluded`]
Excluded(T),
+ /// Mirror of [`Bound::Unbounded`]
Unbounded,
- //workaround types used only as ends_bounds in meta-bound
- //StartBound range searches in overlapping() (non need for
- //reverseIncluded as it would be equivalent to normal included)
+ /// Workaround type used to represent [`Bound::Excluded`] in [`end_bound()`] in meta-bound
+ /// [`BTreeMap::range`] searches in [`crate::RangeBoundsMap::overlapping()`]
+ ///
+ /// [`end_bound()`]: https://doc.rust-lang.org/std/ops/trait.RangeBounds.html#tymethod.end_bound
+ /// [`BTreeMap::range`]: https://doc.rust-lang.org/std/collections/struct.BTreeMap.html#method.range
ReverseExcluded(T),
+ /// Workaround type used to represent [`Bound::Unbounded`] in [`end_bound()`] in meta-bound
+ /// [`BTreeMap::range`] searches in [`crate::RangeBoundsMap::overlapping()`]
+ ///
+ /// [`end_bound()`]: https://doc.rust-lang.org/std/ops/trait.RangeBounds.html#tymethod.end_bound
+ /// [`BTreeMap::range`]: https://doc.rust-lang.org/std/collections/struct.BTreeMap.html#method.range
ReverseUnbounded,
}
impl StartBound {
- //when using this as an end value in a range search
+ /// Converts the [`StartBound`] to the appropriate type for use as
+ /// an [`end_bound()`] in a range search
+ ///
+ /// [`end_bound()`]: https://doc.rust-lang.org/std/ops/trait.RangeBounds.html#tymethod.end_bound
pub(crate) fn as_end_bound(self) -> StartBound {
match self {
//flipping is unnecessary
@@ -48,6 +72,10 @@ impl StartBound {
impl Eq for StartBound where T: PartialEq {}
+/// The [`PartialOrd`] implementaion with the goal of allowing the use
+/// of [`BTreeMap::range`] on [`StartBound`]s
+///
+/// [`BTreeMap::range`]: https://doc.rust-lang.org/std/collections/struct.BTreeMap.html#method.range
#[rustfmt::skip]
impl PartialOrd for StartBound
where
diff --git a/src/lib.rs b/src/lib.rs
index e6f9a98..251a2ea 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -32,7 +32,6 @@ along with range_bounds_map. If not, see .
//!
//! ```
//! # use range_bounds_map::RangeBoundsMap;
-//!
//! let mut range_bounds_map = RangeBoundsMap::new();
//!
//! range_bounds_map.insert(0..5, true);
@@ -48,7 +47,6 @@ along with range_bounds_map. If not, see .
//! # use std::ops::RangeBounds;
//! # use std::ops::Bound;
//! # use range_bounds_map::RangeBoundsMap;
-//!
//! #[derive(Debug)]
//! enum Reservation {
//! // Start, End (Inclusive-Inclusive)
@@ -97,8 +95,8 @@ along with range_bounds_map. If not, see .
//! Most of the [`RangeBounds`]-specific methods on [`RangeBoundsMap`]
//! utilize the [`RangeBoundsMap::overlapping()`] method which
//! internally uses [`BTreeMap`]'s [`range()`] function. To allow
-//! using [`range()`] for this purpose a newtype wrapper wrapped
-//! around the [`start_bound()`]s so that we apply our custom [`Ord`]
+//! using [`range()`] for this purpose a newtype wrapper is wrapped
+//! around the [`start_bound()`]s so that we can apply our custom [`Ord`]
//! implementation onto all the [`start_bound()`]s.
//!
//! # Improvements/Caveats
diff --git a/src/range_bounds_map.rs b/src/range_bounds_map.rs
index fc140b9..c9f9772 100644
--- a/src/range_bounds_map.rs
+++ b/src/range_bounds_map.rs
@@ -60,7 +60,7 @@ where
}
pub fn contains_point(&self, point: &I) -> bool {
- self.get(point).is_some()
+ self.get_at_point(point).is_some()
}
pub fn overlaps(&self, search_range_bounds: &Q) -> bool
@@ -77,6 +77,8 @@ where
where
Q: RangeBounds,
{
+ //todo panic on invalid search range
+
//optimisation fix this without cloning
let start =
StartBound::from(search_range_bounds.start_bound().cloned());
@@ -123,23 +125,13 @@ where
);
}
- pub fn get(&self, point: &I) -> Option<&V> {
- self.get_key_value(point).map(|(_, value)| value)
+ pub fn get_at_point(&self, point: &I) -> Option<&V> {
+ self.get_key_value_at_point(point).map(|(_, value)| value)
}
- pub fn get_key_value(&self, point: &I) -> Option<(&K, &V)> {
- //a zero-range included-included range is equivalent to a point
- return self
- .overlapping(&(
- Bound::Included(point.clone()),
- Bound::Included(point.clone()),
- ))
- .next();
- }
-
- pub fn get_mut(&mut self, point: &I) -> Option<&mut V> {
+ pub fn get_at_point_mut(&mut self, point: &I) -> Option<&mut V> {
if let Some(overlapping_start_bound) =
- self.get_key_value(point).map(|(key, _)| key.start_bound())
+ self.get_key_value_at_point(point).map(|(key, _)| key.start_bound())
{
return self
.starts
@@ -150,6 +142,17 @@ where
return None;
}
+ pub fn get_key_value_at_point(&self, point: &I) -> Option<(&K, &V)> {
+ //a zero-range included-included range is equivalent to a point
+ return self
+ .overlapping(&(
+ Bound::Included(point.clone()),
+ Bound::Included(point.clone()),
+ ))
+ .next();
+ }
+
+
pub fn iter(&self) -> impl Iterator- {
self.starts.iter().map(|(_, (key, value))| (key, value))
}
diff --git a/src/range_bounds_set.rs b/src/range_bounds_set.rs
index 04b8f29..d28122a 100644
--- a/src/range_bounds_set.rs
+++ b/src/range_bounds_set.rs
@@ -21,6 +21,77 @@ use std::ops::RangeBounds;
use crate::range_bounds_map::RangeBoundsMap;
+/// An ordered set of [`RangeBounds`] based on [`BTreeSet`]
+///
+/// # Examples
+/// ```
+/// # use range_bounds_map::RangeBoundsSet;
+/// let mut visits = RangeBoundsSet::new();
+///
+/// // Add some ranges
+/// visits.insert(4..8);
+/// visits.insert(8..18);
+/// visits.insert(20..100);
+///
+/// // Check if a point is contained in the set
+/// if visits.contains_point(&0) {
+/// println!("No visit at the beginning ;(");
+/// }
+///
+/// // Iterate over the ranges overlapping another range
+/// for visit in visits.overlapping(&(2..=8)) {
+/// println!("{visit:?}");
+/// }
+/// ```
+/// Example using a custom [`RangeBounds`] type:
+/// ```
+/// # use std::ops::Bound;
+/// # use std::ops::RangeBounds;
+/// # use ordered_float::NotNan;
+/// # use range_bounds_map::RangeBoundsSet;
+/// // An Exlusive-Exlusive range of [`f32`]s not provided by any
+/// // std::ops ranges
+/// // We use [`ordered_float::NotNan`]s as the inner type must be Ord
+/// // similar to a normal [`BTreeSet`]
+/// struct ExEx {
+/// start: NotNan,
+/// end: NotNan,
+/// }
+/// # impl ExEx {
+/// # fn new(start: f32, end: f32) -> ExEx {
+/// # ExEx {
+/// # start: NotNan::new(start).unwrap(),
+/// # end: NotNan::new(end).unwrap(),
+/// # }
+/// # }
+/// # }
+///
+/// // Implement RangeBounds on our new type
+/// impl RangeBounds> for ExEx {
+/// fn start_bound(&self) -> Bound<&NotNan> {
+/// Bound::Excluded(&self.start)
+/// }
+/// fn end_bound(&self) -> Bound<&NotNan> {
+/// Bound::Excluded(&self.start)
+/// }
+/// }
+///
+/// // Now we can make a [`RangeBoundsSet`] of [`ExEx``]s
+/// let mut set = RangeBoundsSet::new();
+///
+/// set.insert(ExEx::new(0.0, 5.0));
+/// set.insert(ExEx::new(5.0, 7.5));
+///
+/// assert!(NotNan::new(5.0).unwrap() < NotNan::new(5.0).unwrap());
+/// panic!();
+///
+/// assert_eq!(set.contains_point(&(NotNan::new(5.0).unwrap())), false);
+/// assert_eq!(set.contains_point(&(NotNan::new(7.0).unwrap())), true);
+/// assert_eq!(set.contains_point(&(NotNan::new(7.5).unwrap())), false);
+/// ```
+///
+/// [`RangeBounds`]: https://doc.rust-lang.org/std/collections/struct.BTreeSet.html
+/// [`BTreeSet`]: https://doc.rust-lang.org/std/collections/struct.BTreeSet.html
pub struct RangeBoundsSet {
map: RangeBoundsMap,
}
@@ -61,8 +132,8 @@ where
.map(|(key, _)| key)
}
- pub fn get(&self, point: &I) -> Option<&K> {
- self.map.get_key_value(point).map(|(key, _)| key)
+ pub fn get_at_point(&self, point: &I) -> Option<&K> {
+ self.map.get_key_value_at_point(point).map(|(key, _)| key)
}
pub fn contains_point(&self, point: &I) -> bool {