mod value_impls;
use std::convert::TryFrom;
use std::marker::PhantomData;
use crate::error::{AlgorithmError, InternalError};
pub trait Value: Clone {}
pub trait Algorithm {
type Event;
type Action;
type Context;
fn event(
&self,
event: Self::Event,
context: Self::Context,
) -> Result<Vec<Self::Action>, AlgorithmError>;
fn into_algorithm<E, A, C>(self) -> IntoAlgorithm<Self, E, A, C>
where
Self: Sized,
Self::Event: TryFrom<E, Error = InternalError>,
A: TryFrom<Self::Action, Error = InternalError>,
Self::Context: TryFrom<C, Error = InternalError>,
{
IntoAlgorithm {
inner: self,
_event: PhantomData,
_action: PhantomData,
_context: PhantomData,
}
}
}
pub struct IntoAlgorithm<T, E, A, C> {
inner: T,
_event: PhantomData<E>,
_action: PhantomData<A>,
_context: PhantomData<C>,
}
impl<T, E, A, C> Algorithm for IntoAlgorithm<T, E, A, C>
where
T: Algorithm,
<T as Algorithm>::Event: TryFrom<E, Error = InternalError>,
A: TryFrom<<T as Algorithm>::Action, Error = InternalError>,
<T as Algorithm>::Context: TryFrom<C, Error = InternalError>,
{
type Event = E;
type Action = A;
type Context = C;
fn event(
&self,
event: Self::Event,
context: Self::Context,
) -> Result<Vec<Self::Action>, AlgorithmError> {
let inner_event = event.try_into()?;
let inner_context = context.try_into()?;
let inner_actions = self.inner.event(inner_event, inner_context)?;
inner_actions
.into_iter()
.map(|action| {
let res: Result<A, InternalError> = action.try_into();
res
})
.collect::<Result<Vec<Self::Action>, InternalError>>()
.map_err(AlgorithmError::from)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_into_algorithm() -> Result<(), Box<dyn std::error::Error>> {
let algorithm = TestAlgorithm.into_algorithm();
let actions: Vec<Option<String>> = algorithm.event(Some("1"), "1")?;
assert_eq!(actions, vec![Some("2".to_string())]);
let actions = algorithm.event(None, "2")?;
assert_eq!(actions, vec![None]);
Ok(())
}
#[test]
fn test_into_algorithm_err() -> Result<(), Box<dyn std::error::Error>> {
let algorithm = TestAlgorithm.into_algorithm::<_, Option<String>, _>();
assert!(algorithm.event(Some("foo"), "1").is_err());
assert!(algorithm.event(None, "foo").is_err());
Ok(())
}
struct TestEvent(Option<u32>);
struct TestAction(Option<u32>);
struct TestContext(u32);
#[derive(Debug, Eq, PartialEq, Clone)]
struct TestProcess;
struct TestAlgorithm;
impl Algorithm for TestAlgorithm {
type Event = TestEvent;
type Action = TestAction;
type Context = TestContext;
fn event(
&self,
event: Self::Event,
context: Self::Context,
) -> Result<Vec<Self::Action>, AlgorithmError> {
if let TestEvent(Some(i)) = event {
Ok(vec![TestAction(Some(i + context.0))])
} else {
Ok(vec![TestAction(None)])
}
}
}
impl<'a> TryFrom<Option<&'a str>> for TestEvent {
type Error = InternalError;
fn try_from(val: Option<&'a str>) -> Result<Self, Self::Error> {
val.map(|s| {
s.parse::<u32>()
.map_err(|e| InternalError::from_source(Box::new(e)))
})
.transpose()
.map(TestEvent)
}
}
impl TryFrom<TestAction> for Option<String> {
type Error = InternalError;
fn try_from(val: TestAction) -> Result<Self, Self::Error> {
Ok(val.0.map(|i| i.to_string()))
}
}
impl<'a> TryFrom<&'a str> for TestContext {
type Error = InternalError;
fn try_from(val: &'a str) -> Result<Self, Self::Error> {
val.parse::<u32>()
.map_err(|e| InternalError::from_source(Box::new(e)))
.map(TestContext)
}
}
}