added InvalidInsert error for overlapsPreexisting + InvalidRangeBounds types and added larger logo for github social logo thingy
This commit is contained in:
parent
7a416b9f1a
commit
8871d13617
13
README.md
13
README.md
@ -1,12 +1,12 @@
|
||||
# range_bounds_map
|
||||
|
||||
[](https://crates.io/crates/range_bounds_set)
|
||||
[](https://docs.rs/range_bounds_set)
|
||||
|
||||
<p align="center">
|
||||
<img src="logo.svg" alt="range_bounds_map_logo" width="350">
|
||||
</p>
|
||||
|
||||
[](https://crates.io/crates/range_bounds_set)
|
||||
[](https://docs.rs/range_bounds_set)
|
||||
|
||||
This crate provides [`RangeBoundsMap`] and [`RangeBoundsSet`].
|
||||
|
||||
[`RangeBoundsMap`] is similar to [`BTreeMap`] except [`RangeBoundsMap`]
|
||||
@ -19,7 +19,7 @@ maintaining two invariants:
|
||||
[`RangeBoundsSet`] is like [`RangeBoundsMap`] except it
|
||||
uses `()` as values, as [`BTreeSet`] does for [`BTreeMap`]
|
||||
|
||||
# Example using [`Range`]s
|
||||
## Example using [`Range`]s
|
||||
|
||||
```rust
|
||||
use range_bounds_map::RangeBoundsMap;
|
||||
@ -34,7 +34,7 @@ assert_eq!(range_bounds_map.contains_point(&20), false);
|
||||
assert_eq!(range_bounds_map.contains_point(&5), true);
|
||||
```
|
||||
|
||||
# Example using a custom [`RangeBounds`] type
|
||||
## Example using a custom [`RangeBounds`] type
|
||||
|
||||
```rust
|
||||
use std::ops::{Bound, RangeBounds};
|
||||
@ -118,9 +118,6 @@ To summarise:
|
||||
- `is_subset()`
|
||||
- etc... a bunch more
|
||||
- Sub-optimal use of unnecessary `cloned()` just to placate the borrow checker
|
||||
- The library needs some benchmarks
|
||||
- Insert should panic on "bad" Zero RangeBounds like when start_bound >
|
||||
end_bound or Excluded(x)-Excluded(x) Excluded(x)-Included(x) Included(x)-Excluded(x)
|
||||
- The data structures are lacking a lot of useful traits, such as:
|
||||
- Serde: Serialize and Deserialize
|
||||
- FromIterator
|
||||
|
@ -126,9 +126,6 @@ along with range_bounds_map. If not, see <https://www.gnu.org/licenses/>.
|
||||
//! - `is_subset()`
|
||||
//! - etc... a bunch more
|
||||
//! - Sub-optimal use of unnecessary `cloned()` just to placate the borrow checker
|
||||
//! - The library needs some benchmarks
|
||||
//! - Insert should panic on "bad" Zero RangeBounds like when start_bound >
|
||||
//! end_bound or Excluded(x)-Excluded(x) Excluded(x)-Included(x) Included(x)-Excluded(x)
|
||||
//! - The data structures are lacking a lot of useful traits, such as:
|
||||
//! - Serde: Serialize and Deserialize
|
||||
//! - FromIterator
|
||||
@ -198,4 +195,5 @@ pub mod range_bounds_map;
|
||||
pub mod range_bounds_set;
|
||||
|
||||
pub use crate::range_bounds_map::RangeBoundsMap;
|
||||
pub use crate::range_bounds_map::InsertError;
|
||||
pub use crate::range_bounds_set::RangeBoundsSet;
|
||||
|
@ -63,7 +63,7 @@ use crate::bounds::StartBound;
|
||||
/// // 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`]
|
||||
/// // similar to a normal [`BTreeMap`]
|
||||
/// #[derive(Debug, PartialEq)]
|
||||
/// struct ExEx {
|
||||
/// start: NotNan<f32>,
|
||||
@ -117,6 +117,25 @@ pub struct RangeBoundsMap<I, K, V> {
|
||||
starts: BTreeMap<StartBound<I>, (K, V)>,
|
||||
}
|
||||
|
||||
/// An error type to represent the possible errors from the
|
||||
/// [`RangeBoundsMap::insert()`] function.
|
||||
#[derive(PartialEq, Debug)]
|
||||
pub enum InsertError {
|
||||
/// A `RangeBounds` is invalid if both its `start_bound()`
|
||||
/// AND `end_bound()` are (`Bound::Included` OR `Bound::Exluded`)
|
||||
/// AND the `start` point is >= than the `end`
|
||||
/// point.
|
||||
///
|
||||
/// The one exception to this rule is if both `start_bound()` AND
|
||||
/// `end_bound()` are `Bound::Included` and the `start` point is
|
||||
/// == to the `end` point then it is considered valid despite
|
||||
/// failing the previous rule.
|
||||
InvalidRangeBounds,
|
||||
/// The error given if you try to insert a `RangeBounds` that
|
||||
/// overlaps one or more `RangeBounds` already in the map.
|
||||
OverlapsPreexisting,
|
||||
}
|
||||
|
||||
impl<I, K, V> RangeBoundsMap<I, K, V>
|
||||
where
|
||||
K: RangeBounds<I>,
|
||||
@ -158,25 +177,55 @@ where
|
||||
/// Adds a new (`RangeBounds` `Value`) pair to the map.
|
||||
///
|
||||
/// If the new `RangeBounds` overlaps one or more `RangeBounds`
|
||||
/// already in the set then `Err(())` is returned and the map is
|
||||
/// already in the map then [`InsertError::OverlapsPreexisting`]
|
||||
/// is returned and the map is not updated.
|
||||
///
|
||||
/// If the new `RangeBounds` is invalid then
|
||||
/// [`InsertError::InvalidRangeBounds`] is returned and the map is
|
||||
/// not updated.
|
||||
/// See the [`InsertError::InvalidRangeBounds`] type
|
||||
/// to see what constitutes as an "invalid" `RangeBounds`.
|
||||
///
|
||||
/// # Examples
|
||||
/// ```
|
||||
/// use range_bounds_map::RangeBoundsMap;
|
||||
/// use range_bounds_map::InsertError;
|
||||
///
|
||||
/// let mut range_bounds_map = RangeBoundsMap::new();
|
||||
///
|
||||
/// assert_eq!(range_bounds_map.insert(5..10, 9), Ok(()));
|
||||
/// assert_eq!(range_bounds_map.insert(5..10, 2), Err(()));
|
||||
/// assert_eq!(
|
||||
/// range_bounds_map.insert(5..10, 2),
|
||||
/// Err(InsertError::OverlapsPreexisting)
|
||||
/// );
|
||||
/// assert_eq!(
|
||||
/// range_bounds_map.insert(5..1, 8),
|
||||
/// Err(InsertError::InvalidRangeBounds)
|
||||
/// );
|
||||
/// assert_eq!(range_bounds_map.len(), 1);
|
||||
/// ```
|
||||
pub fn insert(&mut self, range_bounds: K, value: V) -> Result<(), ()> {
|
||||
if self.overlaps(&range_bounds) {
|
||||
return Err(());
|
||||
pub fn insert(
|
||||
&mut self,
|
||||
range_bounds: K,
|
||||
value: V,
|
||||
) -> Result<(), InsertError> {
|
||||
if !is_valid_range_bounds(&range_bounds) {
|
||||
return Err(InsertError::InvalidRangeBounds);
|
||||
}
|
||||
|
||||
//todo panic on invalid inputs
|
||||
if self.overlaps(&range_bounds) {
|
||||
return Err(InsertError::OverlapsPreexisting);
|
||||
}
|
||||
|
||||
//optimisation fix this without cloning
|
||||
let start = StartBound::from(range_bounds.start_bound().cloned());
|
||||
//optimisation fix this without cloning
|
||||
let end =
|
||||
StartBound::from(range_bounds.end_bound().cloned()).as_end_bound();
|
||||
|
||||
if start > end {
|
||||
panic!("Invalid search range bounds!");
|
||||
}
|
||||
|
||||
self.starts.insert(
|
||||
//optimisation fix this without cloning
|
||||
@ -239,6 +288,10 @@ where
|
||||
where
|
||||
Q: RangeBounds<I>,
|
||||
{
|
||||
if !is_valid_range_bounds(search_range_bounds) {
|
||||
panic!("Invalid search range bounds!");
|
||||
}
|
||||
|
||||
//optimisation fix this without cloning
|
||||
let start =
|
||||
StartBound::from(search_range_bounds.start_bound().cloned());
|
||||
@ -246,10 +299,6 @@ where
|
||||
let end = StartBound::from(search_range_bounds.end_bound().cloned())
|
||||
.as_end_bound();
|
||||
|
||||
if start > end {
|
||||
panic!("Invalid search range bounds!");
|
||||
}
|
||||
|
||||
let start_range_bounds = (
|
||||
//Included is lossless regarding meta-bounds searches
|
||||
//which is what we want
|
||||
@ -257,7 +306,7 @@ where
|
||||
Bound::Included(end),
|
||||
);
|
||||
//this range will hold all the ranges we want except possibly
|
||||
//the first RangeBound in the range
|
||||
//the first RangeBounds in the range
|
||||
let most_range_bounds = self.starts.range(start_range_bounds);
|
||||
|
||||
//then we check for this possibly missing range_bounds
|
||||
@ -290,7 +339,7 @@ where
|
||||
}
|
||||
|
||||
/// Returns a reference to the `Value` corresponding to the
|
||||
/// `RangeBounds` in the set that overlaps the given point, if
|
||||
/// `RangeBounds` in the map that overlaps the given point, if
|
||||
/// any.
|
||||
///
|
||||
/// # Examples
|
||||
@ -431,12 +480,26 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
fn is_valid_range_bounds<Q, I>(range_bounds: &Q) -> bool
|
||||
where
|
||||
Q: RangeBounds<I>,
|
||||
I: std::cmp::PartialOrd,
|
||||
{
|
||||
match (range_bounds.start_bound(), range_bounds.end_bound()) {
|
||||
(Bound::Included(start), Bound::Included(end)) => start <= end,
|
||||
(Bound::Included(start), Bound::Excluded(end)) => start < end,
|
||||
(Bound::Excluded(start), Bound::Included(end)) => start < end,
|
||||
(Bound::Excluded(start), Bound::Excluded(end)) => start < end,
|
||||
_ => true,
|
||||
}
|
||||
}
|
||||
|
||||
impl<const N: usize, I, K, V> TryFrom<[(K, V); N]> for RangeBoundsMap<I, K, V>
|
||||
where
|
||||
K: RangeBounds<I>,
|
||||
I: Ord + Clone,
|
||||
{
|
||||
type Error = ();
|
||||
type Error = InsertError;
|
||||
fn try_from(pairs: [(K, V); N]) -> Result<Self, Self::Error> {
|
||||
let mut range_bounds_map = RangeBoundsMap::new();
|
||||
for (range_bounds, value) in pairs {
|
||||
|
@ -20,6 +20,7 @@ along with range_bounds_map. If not, see <https://www.gnu.org/licenses/>.
|
||||
use std::ops::RangeBounds;
|
||||
|
||||
use crate::range_bounds_map::RangeBoundsMap;
|
||||
use crate::InsertError;
|
||||
|
||||
/// An ordered set of [`RangeBounds`] based on [`BTreeSet`]
|
||||
///
|
||||
@ -133,20 +134,34 @@ where
|
||||
/// Adds a new `RangeBounds` to the set.
|
||||
///
|
||||
/// If the new `RangeBounds` overlaps one or more `RangeBounds`
|
||||
/// already in the set then `Err(())` is returned and the set is
|
||||
/// already in the set then [`InsertError::OverlapsPreexisting`]
|
||||
/// is returned and the set is not updated.
|
||||
///
|
||||
/// If the new `RangeBounds` is invalid then
|
||||
/// [`InsertError::InvalidRangeBounds`] is returned and the set is
|
||||
/// not updated.
|
||||
/// See the [`InsertError::InvalidRangeBounds`] type
|
||||
/// to see what constitutes as an "invalid" `RangeBounds`.
|
||||
///
|
||||
/// # Examples
|
||||
/// ```
|
||||
/// use range_bounds_map::RangeBoundsSet;
|
||||
/// use range_bounds_map::InsertError;
|
||||
///
|
||||
/// let mut range_bounds_set = RangeBoundsSet::new();
|
||||
///
|
||||
/// assert_eq!(range_bounds_set.insert(5..10), Ok(()));
|
||||
/// assert_eq!(range_bounds_set.insert(5..10), Err(()));
|
||||
/// assert_eq!(
|
||||
/// range_bounds_set.insert(5..10),
|
||||
/// Err(InsertError::OverlapsPreexisting)
|
||||
/// );
|
||||
/// assert_eq!(
|
||||
/// range_bounds_set.insert(5..1),
|
||||
/// Err(InsertError::InvalidRangeBounds)
|
||||
/// );
|
||||
/// assert_eq!(range_bounds_set.len(), 1);
|
||||
/// ```
|
||||
pub fn insert(&mut self, range_bounds: K) -> Result<(), ()> {
|
||||
pub fn insert(&mut self, range_bounds: K) -> Result<(), InsertError> {
|
||||
self.map.insert(range_bounds, ())
|
||||
}
|
||||
|
||||
@ -217,7 +232,9 @@ where
|
||||
/// assert_eq!(range_bounds_set.get_at_point(&101), None);
|
||||
/// ```
|
||||
pub fn get_at_point(&self, point: &I) -> Option<&K> {
|
||||
self.map.get_range_bounds_value_at_point(point).map(|(key, _)| key)
|
||||
self.map
|
||||
.get_range_bounds_value_at_point(point)
|
||||
.map(|(key, _)| key)
|
||||
}
|
||||
|
||||
/// Returns `true` if the set contains a `RangeBounds` that
|
||||
@ -265,7 +282,7 @@ where
|
||||
K: RangeBounds<I>,
|
||||
I: Ord + Clone,
|
||||
{
|
||||
type Error = ();
|
||||
type Error = InsertError;
|
||||
fn try_from(range_bounds: [K; N]) -> Result<Self, Self::Error> {
|
||||
let mut range_bounds_set = RangeBoundsSet::new();
|
||||
for range_bounds in range_bounds {
|
||||
|
12
todo.txt
12
todo.txt
@ -1,20 +1,18 @@
|
||||
- add github badges including lib.rs
|
||||
- make logo
|
||||
|
||||
- update lines of code figures on docs
|
||||
|
||||
- use it in robot_Sweet_graph for a bit before publishing
|
||||
|
||||
- add issues to github for all the caveats and cloned() optimisations
|
||||
- review caveats again
|
||||
|
||||
- implement specific insert error/overlap error
|
||||
|
||||
- run cargo fmt
|
||||
- run and fix cargo clippy
|
||||
- take a look around idiomatic rust for a bit first
|
||||
|
||||
- fill out github meta data
|
||||
|
||||
- update lines of code figures on docs
|
||||
|
||||
- PUBLISH
|
||||
|
||||
- add links to [`RangeBoundsSet`] and map after docs.rs is live with
|
||||
the docs
|
||||
- add links to [`RangeBoundsSet`] and map after docs.rs is live with the docs
|
||||
|
Loading…
x
Reference in New Issue
Block a user