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}