Skip to main content

libbladerf_rs/
range.rs

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}