use crate::message::Message;
use std::collections::HashMap;
use std::fmt;
use time::OffsetDateTime;
type OperatorResult<T> = std::result::Result<T, OperatorError>;
#[derive(Debug, Clone)]
pub struct OperatorError {
reason: String,
}
impl fmt::Display for OperatorError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "unsuccessful operation: {}", self.reason)
}
}
pub trait Operator {
fn apply(
state: &HashMap<i32, f64>,
idx: i32,
value: f64,
datetime: OffsetDateTime,
) -> OperatorResult<f64>;
}
pub trait Gene {
fn apply_operators(
&self,
state: HashMap<i32, f64>,
update: crate::genes::Message,
) -> OperatorResult<()>;
}
struct GuageOperator {}
impl Operator for GuageOperator {
fn apply(_: &HashMap<i32, f64>, _: i32, value: f64, _: OffsetDateTime) -> OperatorResult<f64> {
Ok(value)
}
}
struct AccumOperator {}
impl Operator for AccumOperator {
fn apply(
state: &HashMap<i32, f64>,
idx: i32,
value: f64,
_: OffsetDateTime,
) -> OperatorResult<f64> {
if let Some(old_val) = state.get(&idx) {
Ok(old_val + value)
} else {
Err(OperatorError {
reason: String::from("idx invalid"),
})
}
}
}
pub struct DefaultGene {}
impl Gene for DefaultGene {
fn apply_operators(&self, mut state: HashMap<i32, f64>, update: Message) -> OperatorResult<()> {
if let Message::Update {
path: _,
datetime,
values,
} = update
{
for &idx in state.clone().keys() {
if let Some(in_val) = values.get(&idx) {
match idx {
i if (100..200).contains(&i) => {
match GuageOperator::apply(&state, i, *in_val, datetime) {
Ok(new_val) => {
state.insert(i, new_val);
}
Err(e) => return Err(e),
}
}
i if (200..300).contains(&i) => {
match AccumOperator::apply(&state, i, *in_val, datetime) {
Ok(new_val) => {
state.insert(i, new_val);
}
Err(e) => return Err(e),
}
}
i => {
return Err(OperatorError {
reason: format!("unsupported idx: {i}"),
})
}
}
} else {
return Err(OperatorError {
reason: String::from("cannot read input value"),
});
}
}
}
Ok(())
}
}
impl DefaultGene {
pub fn new() -> Self {
Self {}
}
}
impl Default for DefaultGene {
fn default() -> Self {
Self::new()
}
}