use serde::{Deserialize, Serialize};
#[derive(Clone, Debug)]
pub enum Channel<T> {
LastValue(T),
Append(Vec<T>),
Reduce {
value: T,
reducer: fn(T, T) -> T,
},
}
impl<T: Clone> Channel<T> {
pub fn last_value(value: T) -> Self {
Self::LastValue(value)
}
pub fn append(values: Vec<T>) -> Self {
Self::Append(values)
}
pub fn reduce(value: T, reducer: fn(T, T) -> T) -> Self {
Self::Reduce { value, reducer }
}
pub fn value(&self) -> &T {
match self {
Self::LastValue(v) => v,
Self::Append(v) => v.first().expect("Append channel must have at least one value"),
Self::Reduce { value, .. } => value,
}
}
pub fn update(&mut self, new_value: T) {
match self {
Self::LastValue(v) => *v = new_value,
Self::Append(v) => v.push(new_value),
Self::Reduce { value, reducer } => {
let old = value.clone();
*value = reducer(old, new_value);
}
}
}
}
pub trait Reducer<T> {
fn reduce(a: T, b: T) -> T;
}
pub struct LastValueReducer;
impl<T> Reducer<T> for LastValueReducer {
fn reduce(_a: T, b: T) -> T {
b
}
}
pub struct AppendReducer;
impl<T> Reducer<Vec<T>> for AppendReducer {
fn reduce(mut a: Vec<T>, mut b: Vec<T>) -> Vec<T> {
a.append(&mut b);
a
}
}
pub struct SumReducer;
impl Reducer<i64> for SumReducer {
fn reduce(a: i64, b: i64) -> i64 {
a + b
}
}
impl Reducer<f64> for SumReducer {
fn reduce(a: f64, b: f64) -> f64 {
a + b
}
}
pub struct MaxReducer;
impl Reducer<i64> for MaxReducer {
fn reduce(a: i64, b: i64) -> i64 {
a.max(b)
}
}
impl Reducer<f64> for MaxReducer {
fn reduce(a: f64, b: f64) -> f64 {
a.max(b)
}
}
pub struct MinReducer;
impl Reducer<i64> for MinReducer {
fn reduce(a: i64, b: i64) -> i64 {
a.min(b)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_last_value_channel() {
let mut channel = Channel::last_value(1);
assert_eq!(*channel.value(), 1);
channel.update(2);
assert_eq!(*channel.value(), 2);
}
#[test]
fn test_append_channel() {
let mut channel = Channel::append(vec![1]);
channel.update(2);
channel.update(3);
if let Channel::Append(values) = channel {
assert_eq!(values, vec![1, 2, 3]);
} else {
panic!("Expected Append channel");
}
}
#[test]
fn test_reduce_channel() {
let mut channel = Channel::reduce(0i64, |a, b| a + b);
channel.update(5);
channel.update(3);
if let Channel::Reduce { value, .. } = channel {
assert_eq!(value, 8);
} else {
panic!("Expected Reduce channel");
}
}
#[test]
fn test_reducer_traits() {
assert_eq!(SumReducer::reduce(5i64, 3i64), 8);
assert_eq!(MaxReducer::reduce(5i64, 3i64), 5);
assert_eq!(MinReducer::reduce(5i64, 3i64), 3);
}
}