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::mem;
118use std::ops::{Bound, RangeBounds, RangeInclusive};
119
120// re-export to be nice!
121pub use crate::builder::*;
122pub use crate::iter::consolidate::checker::column::columns::*;
123pub use crate::iter::consolidate::checker::column::*;
124pub use crate::iter::consolidate::checker::*;
125pub use crate::iter::consolidate::*;
126pub use crate::iter::*;
127pub use crate::utils::*;
128pub mod builder;
129pub mod iter;
130pub mod utils;
131
132/// [Mrs] **Minimal Range Span**
133///
134/// In a nut shell this is the minimal struct to represent a range for [crate].
135/// Requires that [GetBeginEnd] and [std::ops::RangeBounds] be imported to use all implemented traits.
136///
137/// ```
138/// use common_range_tools::{
139///   Mrs,
140///   GetBeginEnd  // only required for the self.get_begin() and self.get_end() methods.
141/// };
142/// use std::ops::{RangeBounds,Bound};
143///
144/// fn main () {
145///    let r=Mrs::new(1,2);
146///    assert_eq!(r.start_bound(),Bound::Included(&1));
147///    assert_eq!(r.end_bound(),Bound::Included(&2));
148///    assert_eq!(r.get_begin(),&1);
149///    assert_eq!(r.get_end(),&2);
150/// }
151///
152/// ```
153pub struct Mrs<T> {
154    a: T,
155    z: T,
156}
157
158/// Proxy data structure for [Mrs].
159pub struct MrsP<'r, T, R: GetBeginEnd<T>> {
160    r: &'r R,
161    _t: PhantomData<T>,
162}
163
164/// This struct acts as an owned wrapper for the [Option::Some] produced by the [Consolidate] Iterator,
165/// which then acts as a normal instance of [GetBeginEnd].
166pub struct ConsolidateMrsP<T, R, S>
167where
168    R: GetBeginEnd<T>,
169    S: RangeBounds<T>,
170{
171    r: R,
172    src: Vec<(usize, S)>,
173    _t: PhantomData<T>,
174}
175
176impl<T, R, S> ConsolidateMrsP<T, R, S>
177where
178    R: GetBeginEnd<T>,
179    S: RangeBounds<T>,
180{
181    /// Wwraps the data set and makes it operate as if it is the instance src.0.
182    pub fn new(src: (R, Vec<(usize, S)>)) -> Self {
183        Self {
184            r: src.0,
185            src: src.1,
186            _t: PhantomData,
187        }
188    }
189
190    /// Converts back to the orignal data set used to create this instance.
191    pub fn as_src(self) -> (R, Vec<(usize, S)>) {
192        return (self.r, self.src);
193    }
194
195    /// Returns a ref to the internal data set.
196    pub fn src(&self) -> &Vec<(usize, S)> {
197        return &self.src;
198    }
199}
200
201impl<T, R: GetBeginEnd<T>, S: RangeBounds<T>> GetBeginEnd<T> for ConsolidateMrsP<T, R, S> {
202    /// Wrapper for internal [Mrs] instance.
203    fn get_begin(&self) -> &T {
204        return self.r.get_begin();
205    }
206
207    /// Wrapper for internal [Mrs] instance.
208    fn get_end(&self) -> &T {
209        return self.r.get_end();
210    }
211
212    /// This will drop the sources if used.
213    /// Consider using [ConsolidateMrsP::as_src] in stead.
214    fn to_tuple(self) -> (T, T) {
215        return self.r.to_tuple();
216    }
217}
218
219impl<T, R: GetBeginEnd<T>, S: RangeBounds<T>> RangeBounds<T> for ConsolidateMrsP<T, R, S> {
220    /// Wraps the return value from self.get_begin() in a [std::ops::Bound::Included].
221    fn start_bound(&self) -> Bound<&T> {
222        return Bound::Included(&self.get_begin());
223    }
224
225    /// Wraps the return value from self.get_end() in a [std::ops::Bound::Included].
226    fn end_bound(&self) -> Bound<&T> {
227        return Bound::Included(&self.get_end());
228    }
229}
230
231impl<'r, T, R: GetBeginEnd<T>> MrsP<'r, T, R> {
232    /// Creates a new instance of [MrsP].
233    pub fn new(r: &R) -> Self {
234        return Self {
235            r: unsafe { mem::transmute(r) },
236            _t: PhantomData,
237        };
238    }
239}
240
241/// Trait used by internals to represent ranges.
242pub trait GetBeginEnd<T> {
243    /// Should return a borrowed instance of the begin value.
244    fn get_begin(&self) -> &T;
245
246    /// Should return a borrowed instance of the end value.
247    fn get_end(&self) -> &T;
248
249    // Returns a tuple containing (self.get_begin(),self.get_end()).
250    fn to_tuple_ref(&self) -> (&T, &T) {
251        return (&self.get_begin(), &self.get_end());
252    }
253
254    // Implementation should  consume self and return a tuple containing (begin,end).
255    fn to_tuple(self) -> (T, T);
256}
257
258impl<T> Mrs<T> {
259    /// Constructs a new [Mrs] instance.
260    pub fn new(a: T, z: T) -> Self {
261        Self { a, z }
262    }
263}
264
265impl<T> From<Mrs<T>> for RangeInclusive<T> {
266    fn from(value: Mrs<T>) -> Self {
267        let (a, z) = value.to_tuple();
268        return RangeInclusive::new(a, z);
269    }
270}
271
272impl<T> From<RangeInclusive<T>> for Mrs<T> {
273    fn from(value: RangeInclusive<T>) -> Self {
274        let (a, z) = value.to_tuple();
275        return Mrs::new(a, z);
276    }
277}
278
279impl<T> From<Mrs<T>> for (T, T) {
280    fn from(value: Mrs<T>) -> Self {
281        return value.to_tuple();
282    }
283}
284
285impl<T> From<(T, T)> for Mrs<T> {
286    fn from(value: (T, T)) -> Mrs<T> {
287        return Mrs::new(value.0, value.1);
288    }
289}
290
291impl<'r, T, R: GetBeginEnd<T>> GetBeginEnd<T> for MrsP<'r, T, R> {
292    /// Wrapper for internal [Mrs] instance.
293    fn get_begin(&self) -> &T {
294        return self.r.get_begin();
295    }
296
297    /// Wrapper for internal [Mrs] instance.
298    fn get_end(&self) -> &T {
299        return self.r.get_end();
300    }
301
302    /// Due to the internals being pointer to the real [GetBeginEnd] instance, this method is ***intentionally unimplemented***
303    /// and will panic if called!.
304    fn to_tuple(self) -> (T, T) {
305        unimplemented!();
306    }
307}
308
309impl<T> GetBeginEnd<T> for Mrs<T> {
310    // Returns a borrowed instance of self.z
311    fn get_begin(&self) -> &T {
312        return &self.a;
313    }
314
315    // Returns a borrowed instance of self.z
316    fn get_end(&self) -> &T {
317        return &self.z;
318    }
319
320    // Consumes the instance of self returing a tuple containing (a,z).
321    fn to_tuple(self) -> (T, T) {
322        return (self.a, self.z);
323    }
324}
325
326impl<T> GetBeginEnd<T> for RangeInclusive<T> {
327    // Returns a borrowed instance of self.z
328    fn get_begin(&self) -> &T {
329        return &self.start();
330    }
331
332    // Returns a borrowed instance of self.z
333    fn get_end(&self) -> &T {
334        return &self.end();
335    }
336
337    // Consumes the instance of self returing a tuple containing (a,z).
338    fn to_tuple(self) -> (T, T) {
339        return self.into_inner();
340    }
341}
342
343impl<T> RangeBounds<T> for Mrs<T> {
344    /// Wraps the return value from self.get_begin() in a [std::ops::Bound::Included].
345    fn start_bound(&self) -> Bound<&T> {
346        return Bound::Included(&self.a);
347    }
348
349    /// Wraps the return value from self.get_end() in a [std::ops::Bound::Included].
350    fn end_bound(&self) -> Bound<&T> {
351        return Bound::Included(&self.z);
352    }
353}