added InvalidInsert error for overlapsPreexisting + InvalidRangeBounds types and added larger logo for github social logo thingy

This commit is contained in:
ripytide 2022-12-02 02:26:28 +00:00
parent 7a416b9f1a
commit 8871d13617
6 changed files with 110 additions and 37 deletions

View File

@ -1,12 +1,12 @@
# range_bounds_map
[![Crates.io](https://img.shields.io/crates/v/range_bounds_set)](https://crates.io/crates/range_bounds_set)
[![Docs](https://docs.rs/range_bounds_set/badge)](https://docs.rs/range_bounds_set)
<p align="center">
<img src="logo.svg" alt="range_bounds_map_logo" width="350">
</p>
[![Crates.io](https://img.shields.io/crates/v/range_bounds_set)](https://crates.io/crates/range_bounds_set)
[![Docs](https://docs.rs/range_bounds_set/badge)](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

BIN
logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

View File

@ -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;

View File

@ -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 {

View File

@ -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 {

View File

@ -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