use crate::actions::FnAction;
use crate::backend::job::InputFlavor;
use std::marker::PhantomData;
pub trait Action: Send {
type Input: Send;
type Output: Send;
fn apply(&mut self, input: Self::Input) -> Self::Output;
fn input_flavor(&self) -> InputFlavor;
fn map<U, F>(self, f: F) -> Map<Self, U, F>
where
Self: Sized,
F: FnMut(Self::Output) -> U + Send,
U: Send,
{
Map {
flow: self,
map: f,
_marker: Default::default(),
}
}
fn chain<F>(self, other: F) -> Chain<Self, F>
where
Self: Sized,
F: Action<Input = Self::Output>,
{
Chain {
flow1: self,
flow2: other,
}
}
}
pub trait Runnable: Action<Input = (), Output = ()> + Sized {
fn run(&mut self) {
self.apply(());
}
}
impl<A: Action<Input = (), Output = ()>> Runnable for A {}
pub trait Consumer<T: Send>: Action<Input = T, Output = ()> + Sized {
fn accept(&mut self, t: T) {
self.apply(t);
}
}
impl<T: Send, A: Action<Input = T, Output = ()>> Consumer<T> for A {}
pub trait Supplier<T: Send>: Action<Input = (), Output = T> + Sized {
fn get(&mut self) -> T {
self.apply(())
}
}
impl<T: Send, A: Action<Input = (), Output = T>> Supplier<T> for A {}
pub type BoxAction<'lf, I, O> = Box<dyn Action<Input = I, Output = O> + 'lf>;
impl<'a, I, O> Action for Box<dyn Action<Input = I, Output = O> + 'a>
where
I: Send + 'a,
O: Send + 'a,
{
type Input = I;
type Output = O;
fn apply(&mut self, input: Self::Input) -> Self::Output {
(**self).apply(input)
}
fn input_flavor(&self) -> InputFlavor {
(**self).input_flavor()
}
}
pub struct Map<F, U, M>
where
F: Action,
U: Send,
M: FnMut(F::Output) -> U + Send,
{
flow: F,
map: M,
_marker: PhantomData<U>,
}
impl<F: Action, U: Send, M: FnMut(F::Output) -> U + Send> Action for Map<F, U, M> {
type Input = F::Input;
type Output = U;
fn apply(&mut self, input: Self::Input) -> Self::Output {
let mid = self.flow.apply(input);
(self.map)(mid)
}
fn input_flavor(&self) -> InputFlavor {
self.flow.input_flavor()
}
}
pub struct Chain<F1, F2>
where
F1: Action,
F2: Action<Input = F1::Output>,
{
flow1: F1,
flow2: F2,
}
impl<F1, F2> Action for Chain<F1, F2>
where
F1: Action,
F2: Action<Input = F1::Output>,
{
type Input = F1::Input;
type Output = F2::Output;
fn apply(&mut self, input: Self::Input) -> Self::Output {
let mid = self.flow1.apply(input);
self.flow2.apply(mid)
}
fn input_flavor(&self) -> InputFlavor {
self.flow1.input_flavor()
}
}
pub struct FnOnceAction<I, O, F>
where
I: Send,
O: Send,
F: FnOnce(I) -> O + Send,
{
input_flavor: InputFlavor,
f: Option<F>,
_marker: PhantomData<(I, O)>,
}
impl<I, O, F> Action for FnOnceAction<I, O, F>
where
I: Send,
O: Send,
F: FnOnce(I) -> O + Send,
{
type Input = I;
type Output = O;
fn apply(&mut self, input: Self::Input) -> Self::Output {
match self.f.take() {
None => {
panic!("This action can not be run twice")
}
Some(f) => f(input),
}
}
fn input_flavor(&self) -> InputFlavor {
self.input_flavor
}
}
pub trait IntoAction<In, Out, Marker>: Sized {
type Action: Action<Input = In, Output = Out>;
fn into_action(self) -> Self::Action;
}
#[doc(hidden)]
pub struct ProducerIntoAction<R>(PhantomData<R>);
impl<R: Send + 'static, F: FnMut() -> R + Send + 'static> IntoAction<(), R, ProducerIntoAction<R>>
for F
{
type Action = FnAction<(), R, Box<dyn FnMut(()) -> R + Send>>;
fn into_action(mut self) -> Self::Action {
FnAction::new(InputFlavor::None, Box::new(move |_: ()| self()))
}
}
#[doc(hidden)]
pub struct FunctionIntoAction<T, R>(PhantomData<(T, R)>);
impl<T: Send + 'static, R: Send + 'static, F: FnMut(T) -> R + Send + 'static>
IntoAction<T, R, FunctionIntoAction<T, R>> for F
{
type Action = FnAction<T, R, F>;
fn into_action(self) -> Self::Action {
FnAction::new(InputFlavor::Single, self)
}
}
impl<A: Action> IntoAction<A::Input, A::Output, ()> for A {
type Action = A;
fn into_action(self) -> Self::Action {
self
}
}