range_bound_cmp 0.1.0

Comparison operations between primitive `Bound` values
Documentation
//! # Range Bound Cmp
//! Comparison operations between primitive `Bound` values.
//!
//! ## Usage
//!
//! `range_bound_cmp` aims to simplify set operations on primitive ranges by providing
//! lower and upper bound specific implementations of `PartialEq`, `Eq`, `PartialOrd` and `Ord`.
//! This allows for comparison of values rather than variants. Take for example the following
//! assertions:
//!
//! ```
//! # use std::ops::Bound;
//! # use range_bound_cmp::{OrdRange, LowerBound, UpperBound};
//! assert!(Bound::Included(9) != Bound::Excluded(10));
//!
//! // The above is `false` for `LowerBound` but `true` for `UpperBound`.
//! assert!(LowerBound(Bound::Included(9)) != LowerBound(Bound::Excluded(10)));
//! assert!(UpperBound(Bound::Included(9)) == UpperBound(Bound::Excluded(10)));
//!
//! // Therefore we can make more assertions for the entire range.
//! assert!(OrdRange::new(0..9) != OrdRange::new(0..10));
//! assert!(OrdRange::new(0..=9) == OrdRange::new(0..10));
//! ```
//!
//! Passing a range into `OrdRange` will wrap the bounds for comparison operations.
//! Use the `RangeBound` implementation on `OrdRange`, or call `take` to return the
//! unwrapped bounds for operations such as slicing into an array. Range bound assertions
//! are particularly useful in the development of range set algorithms. Take for example this
//! naive implementation of `intersection` below:
//!
//! ```
//! # use std::ops::{Bound, RangeBounds};
//! # use range_bound_cmp::{OrdRange, LowerBound, UpperBound};
//! // Our return type.
//! pub type TupleRange<T> = (Bound<T>, Bound<T>);
//!
//! /// Get the range of elements in both sets `a` and `b`.
//! fn intersection(a: impl RangeBounds<usize>, b: impl RangeBounds<usize>) -> OrdRange<usize> {
//!     let a = OrdRange::new(a);
//!     let b = OrdRange::new(b);
//!
//!     // Conversion is infallible for this operation.
//!     OrdRange::try_from((a.start.max(b.start), a.end.min(b.end))).unwrap()
//! }
//!
//! assert_eq!(intersection((0..7), (3..10)).take(), (Bound::Included(3), Bound::Excluded(7)));
//! ```
//!
//! ## Lower and Upper bound conversion
//!
//! Conversion between `LowerBound` and `UpperBound` using `TryFrom` or `TryInto`
//! has the following behaviour:
//! - `Bound` variant is always maintained. `LowerBound::Included(5)` will be
//! converted to `UpperBound::Included(5)` while `LowerBound::Excluded(4)` will
//! be converted to `UpperBound::Excluded(6)`.
//! - `Bound::Unbounded` conversion is always an error. The lower bound of `..10`
//! is **not** equal to the upper bound of `0..`.

mod lower;
mod upper;

mod error;
mod ord_range;

pub use lower::LowerBound;
pub use upper::UpperBound;

pub use error::RangeBoundError;
pub use ord_range::OrdRange;