Skip to main content

common_range_tools/
lib.rs

1//! # Overview
2//! The **common-range-tools** crate, is a library that, can be used to find all common intersections for ranges of generic types.  It interoperates with the built in range types for rust via the [std::ops::RangeBounds] trait.  When working with primitive numbers, the increment and decrementing of values are checked (see [working with floats](#working-with-floats), for the exception).  Support for all primitive number types in rust are implemented via the [NumberIncDecCpCmp] object.
3//!
4//! For dealing with ranges beyond just intersections of
5//! numbers see: [Generic Data Types](#generic-data-types).  For working with custom data structures see: [Beyond Generics](#beyond-generics).
6//! For working with custom Ranges and range factories see: [Internal Range Trait](#internal-range-trait).
7//! For consolidating duplicate and overlapping ranges see [Consolidation of ranges](#consolidation-of-ranges).
8//! For finding intersections between muliple [Iterator] instances, see: [Intersections of multiple Iterators](#intersections-of-multiple-iterators).
9//!
10//! ## Example
11//! This is the most basic example, using the default values from [NumberIncDecCpCmp].  The [OverlapIter] is a [DoubleEndedIterator] and can be reversed.
12#![doc = "```rust\n"]
13#![doc = include_str!("../examples/example.rs")]
14#![doc = "\n```"]
15//!
16//!
17//! ## Any Range Example
18//! This example converts [std::ops::RangeBounds] instances to [std::ops::RangeInclusive].
19//! The bounds to the left or right of .. represent the ($ty::MIN)..($ty::MAX), defined by the [NumberIncDecCpCmp] object.
20//! The min and max numbers can be changed, but this example uses the defaults.
21#![doc = "```rust\n"]
22#![doc = include_str!("../examples/tldr.rs")]
23#![doc = "\n```"]
24//!
25//! ## Numeric Boundries
26//! When working with boundries it is useful to be able to control how ranges are interpeted.  The defaults provided by [NumberIncDecCpCmp] are useful
27//! but do not cover all casees.  The internals of this [crate] allow for setting various options to control how both ranges and intersections are computed.
28//!
29//! In this example we set the following:
30//! | Field | What it does|
31//! |------|----|
32//! | step | sets the value used to progress to the next begin or end value for a given range |
33//! | rebound | sets the value used to redefine a range value fom an instance of: [std::ops::Bound::Excluded] |
34//! | min |  the minimum value for ranges in the context of: **..** |
35//! | max | the maximum vaue for ranges in the context of: **..** |
36#![doc = "```rust\n"]
37#![doc = include_str!("../examples/setting_boundries.rs")]
38#![doc = "\n```"]
39//!
40//! ## Working with Floats
41//! When working with floating points, it's nessesary to understand how floats are handled by the [NumberIncDecCpCmp].
42//! Floating point numbers are in a word *imprecise*; The internals of [NumberIncDecCpCmp] does not check [f32] or [f64] for over or underflow;
43//! The internals of [NumberIncDecCpCmp] simply checks that the values properly increment and decrement.
44#![doc = "```rust\n"]
45#![doc = include_str!("../examples/floats.rs")]
46#![doc = "\n```"]
47//!
48//! ## Generic Data types
49//! The [AnyIncDecCpCmp] object supports working with any data type, provided it implements: [PartialOrd], [std::ops::Add], [std::ops::Sub], [Copy], and [Clone].
50//! When working with generics, the value used by *step* and *rebound* values do not have to be the same type as the *values* used by a range.
51//! A practical example of this is how [std::time::Duration] and [std::time::SystemTime] handle [std::ops::Add] and [std::ops::Sub].  
52//!
53//! This is an example that shows how to use [std::time::Duration] to provide the *step* and *rebound* values and [std::time::SystemTime] to operate as the range *values*:
54#![doc = "```rust\n"]
55#![doc = include_str!("../examples/systemtime.rs")]
56#![doc = "\n```"]
57//! ## Beyond Generics
58//! In some cases the range values do not implement: [PartialOrd], [std::ops::Add], [std::ops::Sub], [Copy], [Clone] or do so in a way
59//! that is incompatable with the required data structure used as a value for the range.  The internals of [OverlapIter] use a proxy layer which can be customized to meet most requirements.
60//! This example shows how to work with ragnes of custom data strcutres.
61#![doc = "```rust\n"]
62#![doc = include_str!("../examples/beyond_any.rs")]
63#![doc = "\n```"]
64//!
65//! ## Internal Range Trait
66//! Rust has no single trait representing rages aside from [std::ops::RangeBounds], which can require recomputing the begin and or end
67//! values of a range on each evaluation.  To work around this the internals of this [crate] use a common trait range type of [GetBeginEnd].
68//! There is also a factory trait for creating the interal range trait type: [GetBeginEndOption].  This example shows how to implement both a
69//! factory of: [GetBeginEndOption] and a range of: [GetBeginEnd].  As a note the [GetBeginEnd] trait is implemnted for [std::ops::RangeInclusive] for the
70//! internals of this [crate].
71#![doc = "```rust\n"]
72#![doc = include_str!("../examples/getbeginend.rs")]
73#![doc = "\n```"]
74//!
75//! ## Consolidation of ranges
76//! The [Consolidate] object can be used to consolidate duplicate and overlapping ranges via an [Iterator] of ranges.
77//! It is recommended to convert an instance of [Consolidate] into an instance of [ConsolidateChecker] instance to verify the integrity of the data returned by the [Iterator].
78//!
79//! The ranges returned by the [Iterator] must be in [ConsolidationOrder].
80//!  - For [ConsolidationOrder::Forward] the expected order is: *start asc, end desc*. For more information see: [crate::sort_forward].
81//!  - For [ConsolidationOrder::Reverse] the expected order is: *end desc, start asc*. For more information see: [crate::sort_reverse].
82//!
83//! This example demonstrates how to use [Consolidate] wrapped in an instance of [ConsolidateChecker] using [ConsolidationOrder::Forward]:
84#![doc = "```rust\n"]
85#![doc = include_str!("../examples/overlaps.rs")]
86#![doc = "\n```"]
87//!
88//! ## Intersections of multiple Iterators
89//! The [Columns] object is a factory can be used to construct an [Iterator] that steps through multiple [Iterator] instances of ranges that can contain duplicate
90//! and overlapping ranges that intersect with one another.  Each [Column] added to [Columns] is wrapped in an instance of [ConsolidateChecker] to ensure that the consolidation is occuring in the expected [ConsolidationOrder].
91//! The ranges returned by the [Iterator] must be in [ConsolidationOrder], see: [Consolidation of ranges](#consolidation-of-ranges) for more information.
92//! Finding the intersections from multiple [Iterator] instances is a complex process and is error prone if the data is not provided in the proper order.
93//!
94//! The ranges returned by each [Iterator] must be in same [ConsolidationOrder] as all other [Iterator] instances.
95//!  - For [ConsolidationOrder::Forward] the expected order is: *start asc, end desc*. For more information see: [crate::sort_forward].
96//!  - For [ConsolidationOrder::Reverse] the expected order is: *end desc, start asc*. For more information see: [crate::sort_reverse].
97//!
98//! This example demonstrates how to create a [ColumnsIter] from a [Columns] instance and walk the results.  This example also
99//! includes an example of how to use [crate::sort_forward].
100//!
101#![doc = "```rust\n"]
102#![doc = include_str!("../examples/columns.rs")]
103#![doc = "\n```"]
104//!
105//! # Motivation
106//! In truth there doesn't seem to be a library on crates.io provides the following functionality:
107//! - A range intersection library that handles columns of [Iterator] ranges and progress through those ranges correctly.   
108//! - An intersection library that could be quickly extended to work with any data structure.  
109//! - An intersection library that can support any range type via a a common trait.
110//! - A reversable range intersection iterator.
111//!
112//! Other implementations:
113//!   - [range-ext](https://docs.rs/range-ext/0.3.0/range_ext/index.html)
114//!   - [range-overlap](https://docs.rs/range-overlap/latest/range_overlap/)
115//!   - [rangetools](https://crates.io/crates/rangetools)
116use std::marker::PhantomData;
117use std::ops::{Bound, RangeBounds, RangeInclusive};
118
119// re-export to be nice!
120pub use crate::builder::*;
121pub use crate::iter::consolidate::checker::column::columns::*;
122pub use crate::iter::consolidate::checker::column::*;
123pub use crate::iter::consolidate::checker::*;
124pub use crate::iter::consolidate::*;
125pub use crate::iter::*;
126pub use crate::utils::*;
127pub mod builder;
128pub mod iter;
129pub mod utils;
130
131/// [Mrs] **Minimal Range Span**
132///
133/// In a nut shell this is the minimal struct to represent a range for [crate].
134/// Requires that [GetBeginEnd] and [std::ops::RangeBounds] be imported to use all implemented traits.
135///
136/// ```
137/// use common_range_tools::{
138///   Mrs,
139///   GetBeginEnd  // only required for the self.get_begin() and self.get_end() methods.
140/// };
141/// use std::ops::{RangeBounds,Bound};
142///
143/// fn main () {
144///    let r=Mrs::new(1,2);
145///    assert_eq!(r.start_bound(),Bound::Included(&1));
146///    assert_eq!(r.end_bound(),Bound::Included(&2));
147///    assert_eq!(r.get_begin(),&1);
148///    assert_eq!(r.get_end(),&2);
149/// }
150///
151/// ```
152pub struct Mrs<T> {
153    a: T,
154    z: T,
155}
156
157/// Proxy data structure for [Mrs].
158pub struct MrsP<'r, T, R: GetBeginEnd<T>> {
159    r: &'r R,
160    _t: PhantomData<T>,
161}
162
163/// This struct acts as an owned wrapper for the [Option::Some] produced by the [Consolidate] Iterator,
164/// which then acts as a normal instance of [GetBeginEnd].
165pub struct ConsolidateMrsP<T, R, S>
166where
167    R: GetBeginEnd<T>,
168    S: RangeBounds<T>,
169{
170    r: R,
171    src: Vec<(usize, S)>,
172    _t: PhantomData<T>,
173}
174
175impl<T, R, S> ConsolidateMrsP<T, R, S>
176where
177    R: GetBeginEnd<T>,
178    S: RangeBounds<T>,
179{
180    /// Wwraps the data set and makes it operate as if it is the instance src.0.
181    pub fn new(src: (R, Vec<(usize, S)>)) -> Self {
182        Self {
183            r: src.0,
184            src: src.1,
185            _t: PhantomData,
186        }
187    }
188
189    /// Converts back to the orignal data set used to create this instance.
190    pub fn as_src(self) -> (R, Vec<(usize, S)>) {
191        return (self.r, self.src);
192    }
193
194    /// Returns a ref to the internal data set.
195    pub fn src(&self) -> &Vec<(usize, S)> {
196        return &self.src;
197    }
198}
199
200impl<T, R: GetBeginEnd<T>, S: RangeBounds<T>> GetBeginEnd<T> for ConsolidateMrsP<T, R, S> {
201    /// Wrapper for internal [Mrs] instance.
202    fn get_begin(&self) -> &T {
203        return self.r.get_begin();
204    }
205
206    /// Wrapper for internal [Mrs] instance.
207    fn get_end(&self) -> &T {
208        return self.r.get_end();
209    }
210
211    /// This will drop the sources if used.
212    /// Consider using [ConsolidateMrsP::as_src] in stead.
213    fn to_tuple(self) -> (T, T) {
214        return self.r.to_tuple();
215    }
216}
217
218impl<T, R: GetBeginEnd<T>, S: RangeBounds<T>> RangeBounds<T> for ConsolidateMrsP<T, R, S> {
219    /// Wraps the return value from self.get_begin() in a [std::ops::Bound::Included].
220    fn start_bound(&self) -> Bound<&T> {
221        return Bound::Included(&self.get_begin());
222    }
223
224    /// Wraps the return value from self.get_end() in a [std::ops::Bound::Included].
225    fn end_bound(&self) -> Bound<&T> {
226        return Bound::Included(&self.get_end());
227    }
228}
229
230impl<'r, T, R: GetBeginEnd<T>> MrsP<'r, T, R> {
231    /// Creates a new instance of [MrsP].
232    pub fn new(r: &'r R) -> Self {
233        return Self { r, _t: PhantomData };
234    }
235}
236
237/// Trait used by internals to represent ranges.
238pub trait GetBeginEnd<T> {
239    /// Should return a borrowed instance of the begin value.
240    fn get_begin(&self) -> &T;
241
242    /// Should return a borrowed instance of the end value.
243    fn get_end(&self) -> &T;
244
245    // Returns a tuple containing (self.get_begin(),self.get_end()).
246    fn to_tuple_ref(&self) -> (&T, &T) {
247        return (&self.get_begin(), &self.get_end());
248    }
249
250    // Implementation should  consume self and return a tuple containing (begin,end).
251    fn to_tuple(self) -> (T, T);
252}
253
254impl<T> Mrs<T> {
255    /// Constructs a new [Mrs] instance.
256    pub fn new(a: T, z: T) -> Self {
257        Self { a, z }
258    }
259}
260
261impl<T> From<Mrs<T>> for RangeInclusive<T> {
262    fn from(value: Mrs<T>) -> Self {
263        let (a, z) = value.to_tuple();
264        return RangeInclusive::new(a, z);
265    }
266}
267
268impl<T> From<RangeInclusive<T>> for Mrs<T> {
269    fn from(value: RangeInclusive<T>) -> Self {
270        let (a, z) = value.to_tuple();
271        return Mrs::new(a, z);
272    }
273}
274
275impl<T> From<Mrs<T>> for (T, T) {
276    fn from(value: Mrs<T>) -> Self {
277        return value.to_tuple();
278    }
279}
280
281impl<T> From<(T, T)> for Mrs<T> {
282    fn from(value: (T, T)) -> Mrs<T> {
283        return Mrs::new(value.0, value.1);
284    }
285}
286
287impl<'r, T, R: GetBeginEnd<T>> GetBeginEnd<T> for MrsP<'r, T, R> {
288    /// Wrapper for internal [Mrs] instance.
289    fn get_begin(&self) -> &T {
290        return self.r.get_begin();
291    }
292
293    /// Wrapper for internal [Mrs] instance.
294    fn get_end(&self) -> &T {
295        return self.r.get_end();
296    }
297
298    /// Due to the internals being pointer to the real [GetBeginEnd] instance, this method is ***intentionally unimplemented***
299    /// and will panic if called!.
300    fn to_tuple(self) -> (T, T) {
301        unimplemented!();
302    }
303}
304
305impl<T> GetBeginEnd<T> for Mrs<T> {
306    // Returns a borrowed instance of self.z
307    fn get_begin(&self) -> &T {
308        return &self.a;
309    }
310
311    // Returns a borrowed instance of self.z
312    fn get_end(&self) -> &T {
313        return &self.z;
314    }
315
316    // Consumes the instance of self returing a tuple containing (a,z).
317    fn to_tuple(self) -> (T, T) {
318        return (self.a, self.z);
319    }
320}
321
322impl<T> GetBeginEnd<T> for RangeInclusive<T> {
323    // Returns a borrowed instance of self.z
324    fn get_begin(&self) -> &T {
325        return &self.start();
326    }
327
328    // Returns a borrowed instance of self.z
329    fn get_end(&self) -> &T {
330        return &self.end();
331    }
332
333    // Consumes the instance of self returing a tuple containing (a,z).
334    fn to_tuple(self) -> (T, T) {
335        return self.into_inner();
336    }
337}
338
339impl<T> RangeBounds<T> for Mrs<T> {
340    /// Wraps the return value from self.get_begin() in a [std::ops::Bound::Included].
341    fn start_bound(&self) -> Bound<&T> {
342        return Bound::Included(&self.a);
343    }
344
345    /// Wraps the return value from self.get_end() in a [std::ops::Bound::Included].
346    fn end_bound(&self) -> Bound<&T> {
347        return Bound::Included(&self.z);
348    }
349}