libbladerf-rs 0.3.0

Fully Rust native BladeRF driver
impl RangeItem {
    pub fn min(&self) -> f64 {
        match self {
            RangeItem::Interval(min, _max) => *min,
            RangeItem::Value(value) => *value,
            RangeItem::Step(min, _max, _step, _scale) => *min,
        }
    }
    pub fn max(&self) -> f64 {
        match self {
            RangeItem::Interval(_min, max) => *max,
            RangeItem::Value(value) => *value,
            RangeItem::Step(_min, max, _step, _scale) => *max,
        }
    }
    pub fn step(&self) -> Option<f64> {
        match self {
            RangeItem::Interval(_min, _max) => None,
            RangeItem::Value(_value) => None,
            RangeItem::Step(_min, _max, step, _scale) => Some(*step),
        }
    }
    pub fn scale(&self) -> Option<f64> {
        match self {
            RangeItem::Interval(_min, _max) => None,
            RangeItem::Value(_value) => None,
            RangeItem::Step(_min, _max, _step, scale) => Some(*scale),
        }
    }
}
impl Range {
    pub fn min(&self) -> Option<f64> {
        self.items
            .iter()
            .reduce(|a, b| if a.min() < b.min() { a } else { b })
            .map(|item| item.min())
    }
    pub fn max(&self) -> Option<f64> {
        self.items
            .iter()
            .reduce(|a, b| if a.max() > b.max() { a } else { b })
            .map(|item| item.max())
    }
    pub fn step(&self) -> Option<f64> {
        self.items.first().and_then(|item| item.step())
    }
    pub fn scale(&self) -> Option<f64> {
        self.items.first().and_then(|item| item.scale())
    }
}
#[derive(Debug, Clone, PartialEq, PartialOrd)]
pub enum RangeItem {
    Interval(f64, f64),
    Value(f64),
    Step(f64, f64, f64, f64),
}
#[derive(Debug, Clone, PartialEq, PartialOrd)]
pub struct Range {
    pub items: Vec<RangeItem>,
}
impl Range {
    pub fn new(items: Vec<RangeItem>) -> Self {
        Self { items }
    }
    pub fn contains(&self, value: f64) -> bool {
        for item in &self.items {
            match *item {
                RangeItem::Interval(a, b) => {
                    if a <= value && value <= b {
                        return true;
                    }
                }
                RangeItem::Value(v) => {
                    if (v - value).abs() <= v.abs().max(value.abs()) * f64::EPSILON * 2.0 {
                        return true;
                    }
                }
                RangeItem::Step(min, max, step, _scale) => {
                    if value < min {
                        continue;
                    }
                    let mut v = min + ((value - min) / step).floor() * step;
                    while v <= max && v <= value {
                        if (v - value).abs() <= v.abs().max(value.abs()) * f64::EPSILON * 2.0 {
                            return true;
                        }
                        v += step;
                    }
                }
            }
        }
        false
    }
    pub fn closest(&self, value: f64) -> Option<f64> {
        fn closer(target: f64, closest: Option<f64>, current: f64) -> f64 {
            match closest {
                Some(c) => {
                    if (target - current).abs() < (c - target).abs() {
                        current
                    } else {
                        c
                    }
                }
                None => current,
            }
        }
        if self.contains(value) {
            Some(value)
        } else {
            let mut close = None;
            for i in self.items.iter() {
                match i {
                    RangeItem::Interval(a, b) => {
                        close = Some(closer(value, close, *a));
                        close = Some(closer(value, close, *b));
                    }
                    RangeItem::Value(a) => {
                        close = Some(closer(value, close, *a));
                    }
                    RangeItem::Step(min, max, step, _scale) => {
                        if value <= *min {
                            close = Some(closer(value, close, *min));
                            continue;
                        }
                        if value >= *max {
                            close = Some(closer(value, close, *max));
                            continue;
                        }
                        let mut v = min + ((value - min) / step).floor() * step;
                        while v <= *max && v <= value + step {
                            close = Some(closer(value, close, v));
                            v += step;
                        }
                    }
                }
            }
            close
        }
    }
    pub fn at_least(&self, value: f64) -> Option<f64> {
        fn closer_at_least(target: f64, closest: Option<f64>, current: f64) -> Option<f64> {
            match closest {
                Some(c) => {
                    if (target - current).abs() < (c - target).abs() && current >= target {
                        Some(current)
                    } else {
                        closest
                    }
                }
                None => {
                    if current >= target {
                        Some(current)
                    } else {
                        None
                    }
                }
            }
        }
        if self.contains(value) {
            Some(value)
        } else {
            let mut close = None;
            for i in self.items.iter() {
                match i {
                    RangeItem::Interval(a, b) => {
                        close = closer_at_least(value, close, *a);
                        close = closer_at_least(value, close, *b);
                    }
                    RangeItem::Value(a) => {
                        close = closer_at_least(value, close, *a);
                    }
                    RangeItem::Step(min, max, step, _scale) => {
                        if value <= *min {
                            close = closer_at_least(value, close, *min);
                            continue;
                        }
                        if value >= *max {
                            close = closer_at_least(value, close, *max);
                            continue;
                        }
                        let mut v = min + ((value - min) / step).floor() * step;
                        while v <= *max && v <= value + step {
                            close = closer_at_least(value, close, v);
                            v += step;
                        }
                    }
                }
            }
            close
        }
    }
    pub fn at_max(&self, value: f64) -> Option<f64> {
        fn closer_at_max(target: f64, closest: Option<f64>, current: f64) -> Option<f64> {
            match closest {
                Some(c) => {
                    if (target - current).abs() < (c - target).abs() && current <= target {
                        Some(current)
                    } else {
                        closest
                    }
                }
                None => {
                    if current <= target {
                        Some(current)
                    } else {
                        None
                    }
                }
            }
        }
        if self.contains(value) {
            Some(value)
        } else {
            let mut close = None;
            for i in self.items.iter() {
                match i {
                    RangeItem::Interval(a, b) => {
                        close = closer_at_max(value, close, *a);
                        close = closer_at_max(value, close, *b);
                    }
                    RangeItem::Value(a) => {
                        close = closer_at_max(value, close, *a);
                    }
                    RangeItem::Step(min, max, step, _scale) => {
                        if value <= *min {
                            close = closer_at_max(value, close, *min);
                            continue;
                        }
                        if value >= *max {
                            close = closer_at_max(value, close, *max);
                            continue;
                        }
                        let mut v = min + ((value - min) / step).floor() * step;
                        while v <= *max && v <= value + step {
                            close = closer_at_max(value, close, v);
                            v += step;
                        }
                    }
                }
            }
            close
        }
    }
    pub fn merge(&mut self, mut r: Range) {
        self.items.append(&mut r.items)
    }
}
#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn contains_empty() {
        let r = Range::new(Vec::new());
        assert!(!r.contains(123.0));
    }
    #[test]
    fn contains() {
        let r = Range::new(vec![
            RangeItem::Value(123.0),
            RangeItem::Interval(23.0, 42.0),
            RangeItem::Step(100.0, 110.0, 1.0, 1.0),
        ]);
        assert!(r.contains(123.0));
        assert!(r.contains(23.0));
        assert!(r.contains(42.0));
        assert!(r.contains(40.0));
        assert!(r.contains(100.0));
        assert!(r.contains(107.0));
        assert!(r.contains(110.0));
        assert!(!r.contains(19.0));
    }
    #[test]
    fn closest() {
        let r = Range::new(vec![
            RangeItem::Value(123.0),
            RangeItem::Interval(23.0, 42.0),
            RangeItem::Step(100.0, 110.0, 1.0, 1.0),
        ]);
        assert_eq!(r.closest(122.0), Some(123.0));
        assert_eq!(r.closest(1_000.0), Some(123.0));
        assert_eq!(r.closest(30.0), Some(30.0));
        assert_eq!(r.closest(20.0), Some(23.0));
        assert_eq!(r.closest(50.0), Some(42.0));
        assert_eq!(r.closest(99.5), Some(100.0));
        assert_eq!(r.closest(105.3), Some(105.0));
        assert_eq!(r.closest(105.8), Some(106.0));
        assert_eq!(r.closest(109.8), Some(110.0));
        assert_eq!(r.closest(113.8), Some(110.0));
    }
    #[test]
    fn at_least() {
        let r = Range::new(vec![
            RangeItem::Value(123.0),
            RangeItem::Interval(23.0, 42.0),
            RangeItem::Step(100.0, 110.0, 1.0, 1.0),
        ]);
        assert_eq!(r.at_least(120.0), Some(123.0));
        assert_eq!(r.at_least(1_000.0), None);
        assert_eq!(r.at_least(30.0), Some(30.0));
        assert_eq!(r.at_least(10.0), Some(23.0));
        assert_eq!(r.at_least(99.0), Some(100.0));
        assert_eq!(r.at_least(105.5), Some(106.0));
    }
    #[test]
    fn at_max() {
        let r = Range::new(vec![
            RangeItem::Value(123.0),
            RangeItem::Interval(23.0, 42.0),
            RangeItem::Step(100.0, 110.0, 1.0, 1.0),
        ]);
        assert_eq!(r.at_max(90.0), Some(42.0));
        assert_eq!(r.at_max(10.0), None);
        assert_eq!(r.at_max(30.0), Some(30.0));
        assert_eq!(r.at_max(50.0), Some(42.0));
        assert_eq!(r.at_max(101.0), Some(101.0));
        assert_eq!(r.at_max(100.3), Some(100.0));
        assert_eq!(r.at_max(111.3), Some(110.0));
    }
}