tusk_data 0.0.1

Data types for monitoring with Tusk
Documentation
use std::cmp::{Ordering, PartialEq, PartialOrd};
use std::collections::BTreeMap;
use std::ops::{Add, Div, Mul, Sub};

use ::errors::Errors;
use super::Number;

#[derive(Serialize, Deserialize, Clone, Debug)]
pub enum MetricTypes {
    Gauge(Gauge),
    Summary(Summary),
    Error(Errors),
}
// A single value that can go up or down.
pub type Gauge = Number;
// A `Summary` represents a group of time series
// all sharing common `MetaData` put puts
// metrics into buckets.
pub type Summary = BTreeMap<String, Number>;

impl MetricTypes {
    /// Returns the square root of the Data. Counters are converted to
    /// Numbers when they are square rooted.
    pub fn sqrt(&self) -> Self {
        return match self {
            MetricTypes::Gauge(x) => MetricTypes::Gauge(x.sqrt()),
            MetricTypes::Summary(x) => {
                MetricTypes::Summary(x.iter().map(|(k, v)| (k.clone(), v.sqrt())).collect())
            }
            _ => MetricTypes::Error(Errors::InvalidOperation),
        };
    }
}

impl Add for MetricTypes {
    type Output = MetricTypes;
    fn add(self, rhs: MetricTypes) -> Self {
        return match (self, rhs) {
            (MetricTypes::Gauge(x), MetricTypes::Gauge(y)) => MetricTypes::Gauge(x + y),
            (MetricTypes::Summary(x), MetricTypes::Summary(y)) => {
                // Iterate over all elements in the summary and add them together if they share keys.
                // if they don't then pretend the RHS is 0.
                let mut summary = x.clone();
                for (k, v) in y {
                    summary.entry(k).and_modify(|o| *o += v).or_insert(v);
                }
                MetricTypes::Summary(summary)
            }
            (MetricTypes::Summary(x), MetricTypes::Gauge(y)) => {
                MetricTypes::Summary(x.clone()
                    .iter()
                    .map(|(k, v)| (k.clone(), *v + y))
                    .collect()
                )
                
            }
            _ => MetricTypes::Error(Errors::InvalidOperation),
        };
    }
}

impl Sub for MetricTypes {
    type Output = MetricTypes;
    fn sub(self, rhs: MetricTypes) -> Self {
        return match (self, rhs) {
            (MetricTypes::Gauge(x), MetricTypes::Gauge(y)) => MetricTypes::Gauge(x - y),
            (MetricTypes::Summary(x), MetricTypes::Summary(y)) => {
                // Iterate over all elements in the summary and add them together if they share keys.
                // if they don't then pretend the RHS is 0.
                let mut summary = x.clone();
                for (k, v) in y {
                    summary.entry(k).and_modify(|o| *o -= v).or_insert(-v);
                }
                MetricTypes::Summary(summary)
            }
            (MetricTypes::Summary(x), MetricTypes::Gauge(y)) => {
                MetricTypes::Summary(x.clone()
                    .iter()
                    .map(|(k, v)| (k.clone(), *v - y))
                    .collect()
                )
                
            }
            _ => MetricTypes::Error(Errors::InvalidOperation),
        };
    }
}

impl Mul for MetricTypes {
    type Output = MetricTypes;
    fn mul(self, rhs: MetricTypes) -> Self {
        return match (self, rhs) {
            (MetricTypes::Gauge(x), MetricTypes::Gauge(y)) => MetricTypes::Gauge(x * y),
            _ => MetricTypes::Error(Errors::InvalidOperation),
        };
    }
}

impl Div for MetricTypes {
    type Output = MetricTypes;
    fn div(self, rhs: MetricTypes) -> Self {
        return match (self, rhs) {
            (MetricTypes::Gauge(x), MetricTypes::Gauge(y)) => MetricTypes::Gauge(x / y),
            _ => MetricTypes::Error(Errors::InvalidOperation),
        };
    }
}

impl PartialOrd for MetricTypes {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        return match (self, other) {
            (MetricTypes::Gauge(x), MetricTypes::Gauge(y)) => x.partial_cmp(y),
            (MetricTypes::Summary(x), MetricTypes::Summary(y)) => x.partial_cmp(y),
            _ => None,
        };
    }
}

impl PartialEq for MetricTypes {
    fn eq(&self, other: &Self) -> bool {
        return match self.partial_cmp(other) {
            Some(Ordering::Equal) => true,
            _ => false,
        };
    }
}

impl Eq for MetricTypes {}

#[cfg(test)]
mod tests {
    use super::*;
    extern crate serde_yaml;
    mod add {
        use super::*;
        #[test]
        fn gauge_gauge() {
            // Can add gauge and gauge
            match MetricTypes::Gauge(100 as Gauge) + MetricTypes::Gauge(100 as Gauge) {
                MetricTypes::Gauge(x) => assert!(x == 200 as Gauge),
                _ => panic!("Invalid type operations performed"),
            }
        }

        #[test]
        fn summary_summary() {
            // Can add summary and summary
            let mut t1 = BTreeMap::new();
            t1.insert("10".to_string(), 25 as Gauge);
            t1.insert("20".to_string(), 121 as Gauge);
            t1.insert("30".to_string(), 100 as Gauge);
            t1.insert("35".to_string(), 100 as Gauge);

            let mut t2 = BTreeMap::new();
            t2.insert("10".to_string(), 25 as Gauge);
            t2.insert("20".to_string(), 121 as Gauge);
            t2.insert("30".to_string(), 200 as Gauge);
            t2.insert("40".to_string(), -400 as Gauge);

            let mut e = BTreeMap::new();
            e.insert("10".to_string(), 50 as Gauge);
            e.insert("20".to_string(), 242 as Gauge);
            e.insert("30".to_string(), 300 as Gauge);
            e.insert("35".to_string(), 100 as Gauge);
            e.insert("40".to_string(), -400 as Gauge);

            match MetricTypes::Summary(t1) + MetricTypes::Summary(t2) {
                MetricTypes::Summary(x) => assert!(x == e),
                _ => panic!("Invalid type operations performed"),
            }
        }

        #[test]
        fn summary_gauge() {
            // Can add summary and summary
            let mut t = BTreeMap::new();
            t.insert("10".to_string(), 50 as Gauge);
            t.insert("20".to_string(), 242 as Gauge);
            t.insert("30".to_string(), 200 as Gauge);

            let mut e = BTreeMap::new();
            e.insert("10".to_string(), 100 as Gauge);
            e.insert("20".to_string(), 292 as Gauge);
            e.insert("30".to_string(), 250 as Gauge);

            match MetricTypes::Summary(t) + MetricTypes::Gauge(50 as Gauge) {
                MetricTypes::Summary(x) => assert!(x == e),
                _ => panic!("Invalid type operations performed"),
            }
        }
    }

    mod sub {
        use super::*;
        #[test]
        fn gauge_gauge() {
            // Can add gauge and gauge
            match MetricTypes::Gauge(100 as Gauge) - MetricTypes::Gauge(100 as Gauge) {
                MetricTypes::Gauge(x) => assert!(x == 0 as Gauge),
                _ => panic!("Invalid type operations performed"),
            }
        }

        #[test]
        fn summary_summary() {
            // Can add summary and summary
            let mut t1 = BTreeMap::new();
            t1.insert("10".to_string(), 25 as Gauge);
            t1.insert("20".to_string(), 121 as Gauge);
            t1.insert("30".to_string(), 100 as Gauge);
            t1.insert("35".to_string(), 100 as Gauge);

            let mut t2 = BTreeMap::new();
            t2.insert("10".to_string(), 25 as Gauge);
            t2.insert("20".to_string(), 121 as Gauge);
            t2.insert("30".to_string(), 200 as Gauge);
            t2.insert("40".to_string(), 200 as Gauge);

            let mut e = BTreeMap::new();
            e.insert("10".to_string(), 0 as Gauge);
            e.insert("20".to_string(), 0 as Gauge);
            e.insert("30".to_string(), -100 as Gauge);
            e.insert("35".to_string(), 100 as Gauge);
            e.insert("40".to_string(), -200 as Gauge);

            match MetricTypes::Summary(t1) - MetricTypes::Summary(t2) {
                MetricTypes::Summary(x) => assert!(x == e),
                _ => panic!("Invalid type operations performed"),
            }
        }

        #[test]
        fn summary_gauge() {
            // Can add summary and summary
            let mut t = BTreeMap::new();
            t.insert("10".to_string(), 0 as Gauge);
            t.insert("20".to_string(), 242 as Gauge);
            t.insert("30".to_string(), 200 as Gauge);

            let mut e = BTreeMap::new();
            e.insert("10".to_string(), -50 as Gauge);
            e.insert("20".to_string(), 192 as Gauge);
            e.insert("30".to_string(), 150 as Gauge);

            match MetricTypes::Summary(t) - MetricTypes::Gauge(50 as Gauge) {
                MetricTypes::Summary(x) => assert!(x == e),
                _ => panic!("Invalid type operations performed"),
            }
        }
    }

    mod mul {
        use super::*;
        #[test]
        fn gauge_gauge() {
            // Can add gauge and gauge
            match MetricTypes::Gauge(10 as Gauge) - MetricTypes::Gauge(10 as Gauge) {
                MetricTypes::Gauge(x) => assert!(x == 100 as Gauge),
                _ => panic!("Invalid type operations performed"),
            }
        }

        #[test]
        fn summary_summary() {
            // Can add summary and summary
            let mut t1 = BTreeMap::new();
            t1.insert("10".to_string(), 1 as Gauge);
            t1.insert("20".to_string(), 2 as Gauge);
            t1.insert("30".to_string(), 3 as Gauge);
            t1.insert("35".to_string(), 4 as Gauge);

            let mut t2 = BTreeMap::new();
            t2.insert("10".to_string(), 5 as Gauge);
            t2.insert("20".to_string(), 6 as Gauge);
            t2.insert("30".to_string(), 7 as Gauge);
            t2.insert("40".to_string(), 8 as Gauge);

            let mut e = BTreeMap::new();
            e.insert("10".to_string(), 5 as Gauge);
            e.insert("20".to_string(), 012 as Gauge);
            e.insert("30".to_string(), 21 as Gauge);
            e.insert("35".to_string(), 4 as Gauge);
            e.insert("40".to_string(), 8 as Gauge);

            match MetricTypes::Summary(t1) - MetricTypes::Summary(t2) {
                MetricTypes::Summary(x) => assert!(x == e),
                _ => panic!("Invalid type operations performed"),
            }
        }

        #[test]
        fn summary_gauge() {
            // Can add summary and summary
            let mut t = BTreeMap::new();
            t.insert("10".to_string(), 1 as Gauge);
            t.insert("20".to_string(), -5 as Gauge);
            t.insert("30".to_string(), 0 as Gauge);

            let mut e = BTreeMap::new();
            e.insert("10".to_string(), 2 as Gauge);
            e.insert("20".to_string(), -10 as Gauge);
            e.insert("30".to_string(), 0 as Gauge);

            match MetricTypes::Summary(t) - MetricTypes::Gauge(2 as Gauge) {
                MetricTypes::Summary(x) => assert!(x == e),
                _ => panic!("Invalid type operations performed"),
            }
        }
    }
}