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),
}
pub type Gauge = Number;
pub type Summary = BTreeMap<String, Number>;
impl MetricTypes {
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)) => {
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)) => {
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() {
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() {
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() {
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() {
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() {
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() {
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() {
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() {
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() {
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"),
}
}
}
}