use super::{Field, FieldType}; use crate::message::wrapper::{Calculation, Operand}; use chrono::{DateTime, Utc}; use std::time::Duration; use uuid::Uuid; #[derive(Clone, Debug)] pub enum CalcValue { Calculate(Calculation), Existing(FieldType), FType(FieldType), None, Value(Field), } impl CalcValue { pub fn get(&self, existing: &Field) -> Field { match self { Self::Calculate(calc) => calc.calculate(existing), Self::Existing(_) => existing.clone(), Self::FType(ftype) => ftype.get_default(), Self::None => Field::None, Self::Value(field) => field.clone(), } } pub fn get_type(&self) -> FieldType { match self { Self::Calculate(calc) => calc.get_type(), Self::Existing(ftype) => ftype.clone(), Self::FType(ftype) => ftype.clone(), Self::None => FieldType::None, Self::Value(field) => field.into(), } } } impl From for CalcValue { fn from(value: Calculation) -> Self { Self::Calculate(value) } } impl From for CalcValue { fn from(value: Field) -> Self { Self::Value(value) } } impl From<&Field> for CalcValue { fn from(value: &Field) -> Self { Self::from(value.clone()) } } impl From for CalcValue { fn from(value: FieldType) -> Self { Self::FType(value) } } impl From for CalcValue { fn from(value: bool) -> Self { let output: Field = value.into(); Self::from(output).into() } } impl From> for CalcValue { fn from(value: DateTime) -> Self { let output: Field = value.into(); Self::from(output).into() } } impl From for CalcValue { fn from(value: Duration) -> Self { let output: Field = value.into(); Self::from(output).into() } } impl From for CalcValue { fn from(value: i128) -> Self { let output: Field = value.into(); Self::from(output).into() } } impl From<&str> for CalcValue { fn from(value: &str) -> Self { let output: Field = value.into(); Self::from(output).into() } } impl From for CalcValue { fn from(value: String) -> Self { let output: Field = value.into(); Self::from(output).into() } } impl From for CalcValue { fn from(value: Uuid) -> Self { let output: Field = value.into(); Self::from(output).into() } } #[cfg(test)] mod calcvalues { use super::*; #[test] fn from_uuid() { let value = Uuid::new_v4(); let expected: Field = value.into(); let result: CalcValue = value.into(); match result.clone() { CalcValue::Value(data) => assert_eq!(data, expected), _ => unreachable!("got {:?}, should have gotten a field", result), } assert_eq!(result.get(&Field::None), expected); } #[test] fn from_str() { let value = "something"; let expected: Field = value.into(); let result: CalcValue = value.into(); match result.clone() { CalcValue::Value(data) => assert_eq!(data, expected), _ => unreachable!("got {:?}, should have gotten a field", result), } assert_eq!(result.get(&Field::None), expected); } #[test] fn from_string() { let value = "data".to_string(); let expected: Field = value.clone().into(); let result: CalcValue = value.into(); match result.clone() { CalcValue::Value(data) => assert_eq!(data, expected), _ => unreachable!("got {:?}, should have gotten a field", result), } assert_eq!(result.get(&Field::None), expected); } #[test] fn from_boolean() { let value = true; let expected: Field = value.clone().into(); let result: CalcValue = value.into(); match result.clone() { CalcValue::Value(data) => assert_eq!(data, expected), _ => unreachable!("got {:?}, should have gotten a field", result), } assert_eq!(result.get(&Field::None), expected); } #[test] fn from_datetime() { let value = Utc::now(); let expected: Field = value.clone().into(); let result: CalcValue = value.into(); match result.clone() { CalcValue::Value(data) => assert_eq!(data, expected), _ => unreachable!("got {:?}, should have gotten a field", result), } assert_eq!(result.get(&Field::None), expected); } #[test] fn from_duration() { let value = Duration::from_secs(5); let expected: Field = value.clone().into(); let result: CalcValue = value.into(); match result.clone() { CalcValue::Value(data) => assert_eq!(data, expected), _ => unreachable!("got {:?}, should have gotten a field", result), } assert_eq!(result.get(&Field::None), expected); } #[test] fn from_integer() { let value: i128 = 5; let expected: Field = value.clone().into(); let result: CalcValue = value.into(); match result.clone() { CalcValue::Value(data) => assert_eq!(data, expected), _ => unreachable!("got {:?}, should have gotten a field", result), } assert_eq!(result.get(&Field::None), expected); } #[test] fn from_calculation() { let duration = Duration::from_secs(300); let start = Utc::now() + duration; let mut calc = Calculation::new(Operand::Add); calc.add_value(FieldType::DateTime).unwrap(); calc.add_value(duration.clone()).unwrap(); let result: CalcValue = calc.into(); let data = match result.get(&Field::None) { Field::DateTime(data) => data, _ => unreachable!(), }; let stop = Utc::now() + duration; assert!( data > start && data < stop, "should be about 5 minutes ahead" ); } }