fx-rs 0.1.1-dev0

Algebraic Effects inspired by Kyo and Fx.go
Documentation
use crate::Fx;
use dyn_clone::{DynClone, clone_trait_object};

impl<'f, S: Clone, V: Clone> Fx<'f, S, V> {
    pub fn via<T, U, H>(self, h: H) -> Fx<'f, T, U>
    where
        T: Clone,
        U: Clone,
        H: Into<Handler<'f, S, T, V, U>>,
    {
        h.into().handle(self)
    }
}

impl<'f, A: Clone, B: Clone, U: Clone, V: Clone> Handler<'f, A, B, U, V> {
    pub fn on_left<S: Clone>(self) -> Handler<'f, (A, S), (B, S), U, V> {
        Handler::new(move |e| e.and_swap().via(self.clone().on_right()).and_swap())
    }

    pub fn on_right<S: Clone>(self) -> Handler<'f, (S, A), (S, B), U, V> {
        Handler::new(move |e| e.and_nest().via(self.clone().on_value()).and_flat())
    }

    pub fn on_value<S: Clone>(self) -> Handler<'f, S, S, Fx<'f, A, U>, Fx<'f, B, V>> {
        Handler::new(move |e: Fx<'f, S, Fx<'f, A, U>>| {
            e.flat_map(|i: Fx<'f, A, U>| Fx::func(move |h: Self| h.handle(i.clone())))
                .and_swap()
                .provide_left(self.clone())
        })
    }
}

impl<'f, A: Clone, B: Clone, U: Clone, V: Clone> Handler<'f, A, B, U, V> {
    pub fn new<F>(f: F) -> Self
    where
        F: FnOnce(Fx<'f, A, U>) -> Fx<'f, B, V> + Clone + 'f,
    {
        Self(Box::new(f))
    }

    pub fn handle(self, e: Fx<'f, A, U>) -> Fx<'f, B, V> {
        self.0(e)
    }

    pub fn clone_boxed(&self) -> Box<dyn FnOnce(Fx<'f, A, U>) -> Fx<'f, B, V> + 'f> {
        self.0.clone()
    }

    pub fn contra_map<S, T, H>(self, h: H) -> Handler<'f, S, B, T, V>
    where
        H: FnOnce(Fx<'f, S, T>) -> Fx<'f, A, U> + Clone + 'f,
        S: Clone,
        T: Clone,
    {
        Handler::new(|e| self.handle(h(e)))
    }

    pub fn map<S, T, H>(self, h: H) -> Handler<'f, A, S, U, T>
    where
        H: FnOnce(Fx<'f, B, V>) -> Fx<'f, S, T> + Clone + 'f,
        S: Clone,
        T: Clone,
    {
        Handler::new(|e| h(self.handle(e)))
    }
}

#[derive(Clone)]
pub struct Handler<'f, A: Clone, B: Clone, U: Clone, V: Clone>(
    Box<dyn HandlerFn<'f, A, B, U, V> + 'f>,
);

clone_trait_object!(<'f, A: Clone, B: Clone, U:Clone, V:Clone> HandlerFn<'f, A, B, U, V>);
trait HandlerFn<'f, A, B, U, V>: DynClone + FnOnce(Fx<'f, A, U>) -> Fx<'f, B, V> + 'f
where
    V: Clone + 'f,
    U: Clone + 'f,
    A: Clone + 'f,
    B: Clone + 'f,
{
}
impl<'f, A, B, U, V, F> HandlerFn<'f, A, B, U, V> for F
where
    F: FnOnce(Fx<'f, A, U>) -> Fx<'f, B, V> + Clone + 'f,
    V: Clone + 'f,
    U: Clone + 'f,
    A: Clone + 'f,
    B: Clone + 'f,
{
}

impl<'f, A, B, U, V, F> From<F> for Handler<'f, A, B, U, V>
where
    F: FnOnce(Fx<'f, A, U>) -> Fx<'f, B, V> + Clone + 'f,
    V: Clone + 'f,
    U: Clone + 'f,
    A: Clone + 'f,
    B: Clone + 'f,
{
    fn from(value: F) -> Self {
        Handler::new(value)
    }
}

impl<'f, A, B, U, V> From<Handler<'f, A, B, U, V>> for Box<dyn HandlerFn<'f, A, B, U, V> + 'f>
where
    V: Clone + 'f,
    U: Clone + 'f,
    A: Clone + 'f,
    B: Clone + 'f,
{
    fn from(value: Handler<'f, A, B, U, V>) -> Self {
        value.0
    }
}