1impl RangeItem {
2 pub fn min(&self) -> f64 {
3 match self {
4 RangeItem::Interval(min, _max) => *min,
5 RangeItem::Value(value) => *value,
6 RangeItem::Step(min, _max, _step, _scale) => *min,
7 }
8 }
9 pub fn max(&self) -> f64 {
10 match self {
11 RangeItem::Interval(_min, max) => *max,
12 RangeItem::Value(value) => *value,
13 RangeItem::Step(_min, max, _step, _scale) => *max,
14 }
15 }
16 pub fn step(&self) -> Option<f64> {
17 match self {
18 RangeItem::Interval(_min, _max) => None,
19 RangeItem::Value(_value) => None,
20 RangeItem::Step(_min, _max, step, _scale) => Some(*step),
21 }
22 }
23 pub fn scale(&self) -> Option<f64> {
24 match self {
25 RangeItem::Interval(_min, _max) => None,
26 RangeItem::Value(_value) => None,
27 RangeItem::Step(_min, _max, _step, scale) => Some(*scale),
28 }
29 }
30}
31impl Range {
32 pub fn min(&self) -> Option<f64> {
33 self.items
34 .iter()
35 .reduce(|a, b| if a.min() < b.min() { a } else { b })
36 .map(|item| item.min())
37 }
38 pub fn max(&self) -> Option<f64> {
39 self.items
40 .iter()
41 .reduce(|a, b| if a.max() > b.max() { a } else { b })
42 .map(|item| item.max())
43 }
44 pub fn step(&self) -> Option<f64> {
45 self.items.first().and_then(|item| item.step())
46 }
47 pub fn scale(&self) -> Option<f64> {
48 self.items.first().and_then(|item| item.scale())
49 }
50}
51#[derive(Debug, Clone, PartialEq, PartialOrd)]
52pub enum RangeItem {
53 Interval(f64, f64),
54 Value(f64),
55 Step(f64, f64, f64, f64),
56}
57#[derive(Debug, Clone, PartialEq, PartialOrd)]
58pub struct Range {
59 pub items: Vec<RangeItem>,
60}
61impl Range {
62 pub fn new(items: Vec<RangeItem>) -> Self {
63 Self { items }
64 }
65 pub fn contains(&self, value: f64) -> bool {
66 for item in &self.items {
67 match *item {
68 RangeItem::Interval(a, b) => {
69 if a <= value && value <= b {
70 return true;
71 }
72 }
73 RangeItem::Value(v) => {
74 if (v - value).abs() <= f64::EPSILON {
75 return true;
76 }
77 }
78 RangeItem::Step(min, max, step, _scale) => {
79 if value < min {
80 continue;
81 }
82 let mut v = min + ((value - min) / step).floor() * step;
83 while v <= max && v <= value {
84 if (v - value).abs() <= f64::EPSILON {
85 return true;
86 }
87 v += step;
88 }
89 }
90 }
91 }
92 false
93 }
94 pub fn closest(&self, value: f64) -> Option<f64> {
95 fn closer(target: f64, closest: Option<f64>, current: f64) -> f64 {
96 match closest {
97 Some(c) => {
98 if (target - current).abs() < (c - target).abs() {
99 current
100 } else {
101 c
102 }
103 }
104 None => current,
105 }
106 }
107 if self.contains(value) {
108 Some(value)
109 } else {
110 let mut close = None;
111 for i in self.items.iter() {
112 match i {
113 RangeItem::Interval(a, b) => {
114 close = Some(closer(value, close, *a));
115 close = Some(closer(value, close, *b));
116 }
117 RangeItem::Value(a) => {
118 close = Some(closer(value, close, *a));
119 }
120 RangeItem::Step(min, max, step, _scale) => {
121 if value <= *min {
122 close = Some(closer(value, close, *min));
123 continue;
124 }
125 if value >= *max {
126 close = Some(closer(value, close, *max));
127 continue;
128 }
129 let mut v = min + ((value - min) / step).floor() * step;
130 while v <= *max && v <= value + step {
131 close = Some(closer(value, close, v));
132 v += step;
133 }
134 }
135 }
136 }
137 close
138 }
139 }
140 pub fn at_least(&self, value: f64) -> Option<f64> {
141 fn closer_at_least(target: f64, closest: Option<f64>, current: f64) -> Option<f64> {
142 match closest {
143 Some(c) => {
144 if (target - current).abs() < (c - target).abs() && current >= target {
145 Some(current)
146 } else {
147 closest
148 }
149 }
150 None => {
151 if current >= target {
152 Some(current)
153 } else {
154 None
155 }
156 }
157 }
158 }
159 if self.contains(value) {
160 Some(value)
161 } else {
162 let mut close = None;
163 for i in self.items.iter() {
164 match i {
165 RangeItem::Interval(a, b) => {
166 close = closer_at_least(value, close, *a);
167 close = closer_at_least(value, close, *b);
168 }
169 RangeItem::Value(a) => {
170 close = closer_at_least(value, close, *a);
171 }
172 RangeItem::Step(min, max, step, _scale) => {
173 if value <= *min {
174 close = closer_at_least(value, close, *min);
175 continue;
176 }
177 if value >= *max {
178 close = closer_at_least(value, close, *max);
179 continue;
180 }
181 let mut v = min + ((value - min) / step).floor() * step;
182 while v <= *max && v <= value + step {
183 close = closer_at_least(value, close, v);
184 v += step;
185 }
186 }
187 }
188 }
189 close
190 }
191 }
192 pub fn at_max(&self, value: f64) -> Option<f64> {
193 fn closer_at_max(target: f64, closest: Option<f64>, current: f64) -> Option<f64> {
194 match closest {
195 Some(c) => {
196 if (target - current).abs() < (c - target).abs() && current <= target {
197 Some(current)
198 } else {
199 closest
200 }
201 }
202 None => {
203 if current <= target {
204 Some(current)
205 } else {
206 None
207 }
208 }
209 }
210 }
211 if self.contains(value) {
212 Some(value)
213 } else {
214 let mut close = None;
215 for i in self.items.iter() {
216 match i {
217 RangeItem::Interval(a, b) => {
218 close = closer_at_max(value, close, *a);
219 close = closer_at_max(value, close, *b);
220 }
221 RangeItem::Value(a) => {
222 close = closer_at_max(value, close, *a);
223 }
224 RangeItem::Step(min, max, step, _scale) => {
225 if value <= *min {
226 close = closer_at_max(value, close, *min);
227 continue;
228 }
229 if value >= *max {
230 close = closer_at_max(value, close, *max);
231 continue;
232 }
233 let mut v = min + ((value - min) / step).floor() * step;
234 while v <= *max && v <= value + step {
235 close = closer_at_max(value, close, v);
236 v += step;
237 }
238 }
239 }
240 }
241 close
242 }
243 }
244 pub fn merge(&mut self, mut r: Range) {
245 self.items.append(&mut r.items)
246 }
247}
248#[cfg(test)]
249mod tests {
250 use super::*;
251 #[test]
252 fn contains_empty() {
253 let r = Range::new(Vec::new());
254 assert!(!r.contains(123.0));
255 }
256 #[test]
257 fn contains() {
258 let r = Range::new(vec![
259 RangeItem::Value(123.0),
260 RangeItem::Interval(23.0, 42.0),
261 RangeItem::Step(100.0, 110.0, 1.0, 1.0),
262 ]);
263 assert!(r.contains(123.0));
264 assert!(r.contains(23.0));
265 assert!(r.contains(42.0));
266 assert!(r.contains(40.0));
267 assert!(r.contains(100.0));
268 assert!(r.contains(107.0));
269 assert!(r.contains(110.0));
270 assert!(!r.contains(19.0));
271 }
272 #[test]
273 fn closest() {
274 let r = Range::new(vec![
275 RangeItem::Value(123.0),
276 RangeItem::Interval(23.0, 42.0),
277 RangeItem::Step(100.0, 110.0, 1.0, 1.0),
278 ]);
279 assert_eq!(r.closest(122.0), Some(123.0));
280 assert_eq!(r.closest(1000.0), Some(123.0));
281 assert_eq!(r.closest(30.0), Some(30.0));
282 assert_eq!(r.closest(20.0), Some(23.0));
283 assert_eq!(r.closest(50.0), Some(42.0));
284 assert_eq!(r.closest(99.5), Some(100.0));
285 assert_eq!(r.closest(105.3), Some(105.0));
286 assert_eq!(r.closest(105.8), Some(106.0));
287 assert_eq!(r.closest(109.8), Some(110.0));
288 assert_eq!(r.closest(113.8), Some(110.0));
289 }
290 #[test]
291 fn at_least() {
292 let r = Range::new(vec![
293 RangeItem::Value(123.0),
294 RangeItem::Interval(23.0, 42.0),
295 RangeItem::Step(100.0, 110.0, 1.0, 1.0),
296 ]);
297 assert_eq!(r.at_least(120.0), Some(123.0));
298 assert_eq!(r.at_least(1000.0), None);
299 assert_eq!(r.at_least(30.0), Some(30.0));
300 assert_eq!(r.at_least(10.0), Some(23.0));
301 assert_eq!(r.at_least(99.0), Some(100.0));
302 assert_eq!(r.at_least(105.5), Some(106.0));
303 }
304 #[test]
305 fn at_max() {
306 let r = Range::new(vec![
307 RangeItem::Value(123.0),
308 RangeItem::Interval(23.0, 42.0),
309 RangeItem::Step(100.0, 110.0, 1.0, 1.0),
310 ]);
311 assert_eq!(r.at_max(90.0), Some(42.0));
312 assert_eq!(r.at_max(10.0), None);
313 assert_eq!(r.at_max(30.0), Some(30.0));
314 assert_eq!(r.at_max(50.0), Some(42.0));
315 assert_eq!(r.at_max(101.0), Some(101.0));
316 assert_eq!(r.at_max(100.3), Some(100.0));
317 assert_eq!(r.at_max(111.3), Some(110.0));
318 }
319}