1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
//! # 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..`.
pub use LowerBound;
pub use UpperBound;
pub use RangeBoundError;
pub use OrdRange;