pipes 0.0.1

Stream-based programming with compositional pipelines in Rust
use self::Sig::{
    Request,
    Respond,
};

pub enum Sig<'a, OU, IU, ID, OD, X> {
    Request(OU, Box<FnOnce<(IU,), X> + 'a>),
    Respond(OD, Box<FnOnce<(ID,), X> + 'a>),
}

#[inline]
pub fn map<'a, OU, IU, ID, OD, X, Y, F:'a>(
    m: Sig<'a, OU, IU, ID, OD, X>,
    f: F
) -> Sig<'a, OU, IU, ID, OD, Y>
    where
        F: FnOnce(X) -> Y,
{
    match m {
        Request(ou, giu) => Request(ou, box move |:iu| f(giu.call_once((iu,)))),
        Respond(od, gid) => Respond(od, box move |:id| f(gid.call_once((id,)))),
    }
}

monad!(Proxy, Sig, map, [ OU, IU, ID, OD, ])

pub struct Void;

pub type Effect  <'a,                 R> = Proxy<'a, Void, (), (), Void, R>;
pub type Producer<'a,             OD, R> = Proxy<'a, Void, (), (), OD  , R>;
pub type Pipe    <'a, IU,         OD, R> = Proxy<'a, ()  , IU, (), OD  , R>;
pub type Consumer<'a, IU,             R> = Proxy<'a, ()  , IU, (), Void, R>;
pub type Client  <'a, OU, IU,         R> = Proxy<'a, OU  , IU, (), Void, R>;
pub type Server  <'a,         ID, OD, R> = Proxy<'a, Void, (), ID, OD  , R>;

#[inline]
pub fn request<'a, OU, IU, ID, OD>(ou: OU) -> Proxy<'a, OU, IU, ID, OD, IU> {
    wrap(Request(ou, box |:iu| box
    point(iu)))
}

#[inline]
pub fn respond<'a, OU, IU, ID, OD>(od: OD) -> Proxy<'a, OU, IU, ID, OD, ID> {
    wrap(Respond(od, box |:id| box
    point(id)))
}

#[inline]
pub fn push<'a, OU, IU, R>(iu: IU) -> Proxy<'a, OU, IU, OU, IU, R> {
    wrap(Respond(iu, box |:ou| box
    wrap(Request(ou, box |:iu| box
    push(iu)))))
}

#[inline]
pub fn pull<'a, OU, IU, R>(ou: OU) -> Proxy<'a, OU, IU, OU, IU, R> {
    wrap(Request(ou, box |:iu| box
    wrap(Respond(iu, box |:ou| box
    pull(ou)))))
}

#[inline]
pub fn closed<A>(_: Void) -> A {
    loop {}
}

impl<'a, R:'a> Effect<'a, R> {
    #[inline]
    pub fn run(self) -> R {
        self.go(|&:x| { match x {
            Request(v, _) => closed(v),
            Respond(v, _) => closed(v),
        }})
    }
}