rangemap/lib.rs
1/*!
2[`RangeMap`] and [`RangeInclusiveMap`] are map data structures whose keys
3are stored as ranges. Contiguous and overlapping ranges that map to the same
4value are coalesced into a single range.
5
6Corresponding [`RangeSet`] and [`RangeInclusiveSet`] structures are also provided.
7
8
9# Different kinds of ranges
10
11`RangeMap` and `RangeInclusiveMap` correspond to the [`Range`]
12and [`RangeInclusive`] types from the standard library respectively.
13For some applications the choice of range type may be obvious,
14or even be dictated by pre-existing design decisions. For other applications
15the choice may seem arbitrary, and be guided instead by convenience or
16aesthetic preference.
17
18If the choice is not obvious in your case, consider these differences:
19
20- If your key type `K` represents points on a continuum (e.g. `f64`),
21 and the choice of which of two adjacent ranges "owns" the value
22 where they touch is largely arbitrary, then it may be more natural
23 to work with half-open `Range`s like `0.0..1.0` and `1.0..2.0`. If you
24 were to use closed `RangeInclusive`s here instead, then to represent two such adjacent
25 ranges you would need to subtract some infinitesimal (which may depend,
26 as it does in the case of `f64`, on the specific value of `K`)
27 from the end of the earlier range. (See the last point below for more
28 on this problem.)
29- If you need to represent ranges that _include_ the maximum
30 value in the key domain (e.g. `255u8`) then you will
31 probably want to use `RangeInclusive`s like `128u8..=255u8`. Sometimes
32 it may be possible to instead work around this by using a wider key
33 type than the values you are actually trying to represent (`K=u16`
34 even though you are only trying to represent ranges covering `u8`)
35 but in these cases the key domain often represents discrete objects
36 rather than points on a continuum, and so `RangeInclusive` may
37 be a more natural way to express these ranges anyway.
38- If you are using `RangeInclusive`, then it must be possible to define
39 _successor_ and _predecessor_ functions for your key type `K`,
40 because adjacent ranges can not be detected (and thereby coalesced)
41 simply by testing their ends for equality. For key types that represent
42 points on a continuum, defining these functions may be awkward and error-prone.
43 For key types that represent discrete objects, this is usually much
44 more straightforward.
45
46
47# Example: use with Chrono
48
49```rust
50use chrono::offset::TimeZone;
51use chrono::{Duration, Utc};
52use rangemap::RangeMap;
53
54let people = ["Alice", "Bob", "Carol"];
55let mut roster = RangeMap::new();
56
57// Set up initial roster.
58let start_of_roster = Utc.ymd(2019, 1, 7);
59let mut week_start = start_of_roster;
60for _ in 0..3 {
61 for person in &people {
62 let next_week = week_start + Duration::weeks(1);
63 roster.insert(week_start..next_week, person);
64 week_start = next_week;
65 }
66}
67
68// Bob is covering Alice's second shift (the fourth shift overall).
69let fourth_shift_start = start_of_roster + Duration::weeks(3);
70let fourth_shift_end = fourth_shift_start + Duration::weeks(1);
71roster.insert(fourth_shift_start..fourth_shift_end, &"Bob");
72
73for (range, person) in roster.iter() {
74 println!("{} ({}): {}", range.start, range.end - range.start, person);
75}
76
77// Output:
78// 2019-01-07UTC (P7D): Alice
79// 2019-01-14UTC (P7D): Bob
80// 2019-01-21UTC (P7D): Carol
81// 2019-01-28UTC (P14D): Bob
82// 2019-02-11UTC (P7D): Carol
83// 2019-02-18UTC (P7D): Alice
84// 2019-02-25UTC (P7D): Bob
85// 2019-03-04UTC (P7D): Carol
86```
87
88
89## Crate features
90
91By default this crate has no dependencies on other crates.
92
93If you enable the **serde1** feature it will introduce a dependency on
94the _serde_ crate and provide `Serialize` and `Deserialize`
95implementations for all map and set types in this crate.
96
97You can enable the **serde1** feature in your _Cargo.toml_ file like so:
98
99```toml
100[dependencies]
101rangemap = { version = "1", features = ["serde1"] }
102```
103
104You can similarly enable support for _quickcheck_ by enabling
105the **quickcheck** feature.
106
107
108## Building without the Rust standard library
109
110This crate can work without the full standard library available
111(e.g. when running on bare metal without an operating system)
112but relies on the presence of a global allocator —
113i.e. it links the `core` and `alloc` crates, but not `std`.
114
115Presently there is no functionality in the crate that require
116the standard library. Such functionality will likely be
117introduced in the future, and will be gated behind a default-on
118`std` feature.
119
120See [The Rust Programming Language](https://doc.rust-lang.org/1.7.0/book/no-stdlib.html)
121book for general information about operating without the standard library.
122
123
124
125[`RangeMap`]: crate::RangeMap
126[`RangeInclusiveMap`]: crate::RangeInclusiveMap
127[`RangeSet`]: crate::RangeSet
128[`RangeInclusiveSet`]: crate::RangeInclusiveSet
129[`Range`]: core::ops::Range
130[`RangeInclusive`]: core::ops::RangeInclusive
131
132*/
133
134#![no_std]
135extern crate alloc;
136
137pub mod inclusive_map;
138pub mod inclusive_set;
139pub mod map;
140pub(crate) mod operations;
141pub mod set;
142
143#[cfg(test)]
144mod dense;
145mod range_wrapper;
146mod std_ext;
147
148pub use inclusive_map::RangeInclusiveMap;
149pub use inclusive_set::RangeInclusiveSet;
150pub use map::RangeMap;
151pub use set::RangeSet;
152pub use std_ext::{StepFns, StepLite};
153
154// Doc tests for README.
155#[cfg(feature = "nightly")]
156mod readme;