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 Itertors](#intersections-of-multiple-itertors).
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 instances called [GetBeginEndOption]. This example shows how to create and use both the
69//! factory: [GetBeginEndOption] and the range: [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 Itertors
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}