use anyhow::Result;
use async_trait::async_trait;
use crate::{
operation::{Monoid, Operation},
runtime::Runtime,
};
#[async_trait]
pub trait Directive {
type Input;
type Output;
fn map<'a, Op, F>(self, op: &'a Op) -> Map<'a, Op, Self>
where
Op: Operation,
F: Functor<'a, Op::Output, A = Op::Input>,
Self: Sized + Directive<Output = F>,
{
Map { op, input: self }
}
fn fold<'a, M, F>(self, m: &'a M) -> Fold<'a, M, Self>
where
M: Monoid,
F: Foldable<'a, M::Elem, A = M::Elem>,
Self: Sized + Directive<Output = F>,
{
Fold { m, input: self }
}
async fn run(self, runtime: &Runtime) -> Result<Self::Output>;
}
macro_rules! impl_lit {
($struct_name:ident) => {
#[async_trait::async_trait]
impl $crate::directive::Directive for $struct_name {
type Input = Self;
type Output = Self;
async fn run(self, _: &$crate::runtime::Runtime) -> anyhow::Result<Self::Output> {
Ok(self)
}
}
};
($struct_name:ident<$($generics:ident),+>) => {
#[async_trait::async_trait]
impl<$($generics: Send),+> $crate::directive::Directive for $struct_name<$($generics),+> {
type Input = Self;
type Output = Self;
async fn run(self, _: &$crate::runtime::Runtime) -> anyhow::Result<Self::Output> {
Ok(self)
}
}
};
($struct_name:ident<$lifetime:tt, $($generics:ident),+>) => {
#[async_trait::async_trait]
impl<$lifetime, $($generics: Send),+> $crate::directive::Directive for $struct_name<$lifetime, $($generics),+> {
type Input = Self;
type Output = Self;
async fn run(self, _: &$crate::runtime::Runtime) -> anyhow::Result<Self::Output> {
Ok(self)
}
}
};
}
pub trait HKT<U> {
type A;
type Target;
}
macro_rules! impl_hkt {
($t: ident) => {
impl<T, U> $crate::directive::HKT<U> for $t<T> {
type A = T;
type Target = $t<U>;
}
};
($t: ident<$lifetime:tt>) => {
impl<$lifetime, T: $lifetime, U: $lifetime> $crate::directive::HKT<U> for $t<$lifetime, T> {
type A = T;
type Target = $t<$lifetime, U>;
}
};
}
#[async_trait]
pub trait Functor<'a, B>: HKT<B> {
async fn f_map<Op>(self, op: &'a Op, runtime: &Runtime) -> Result<Self::Target>
where
Op: Operation<Input = Self::A, Output = B>;
}
pub struct Map<'a, Op, D> {
op: &'a Op,
input: D,
}
#[async_trait]
impl<
'a,
Op: Operation,
F: Functor<'a, Op::Output, A = Op::Input> + Send,
D: Directive<Output = F> + Send,
> Directive for Map<'a, Op, D>
{
type Input = F;
type Output = F::Target;
async fn run(self, runtime: &Runtime) -> Result<Self::Output> {
self.input.run(runtime).await?.f_map(self.op, runtime).await
}
}
#[async_trait]
pub trait Foldable<'a, B>: HKT<B> {
async fn f_fold<M>(self, m: &'a M, runtime: &Runtime) -> Result<Self::A>
where
M: Monoid<Elem = Self::A> + 'static;
}
pub struct Fold<'a, M, D> {
m: &'a M,
input: D,
}
#[async_trait]
impl<
'a,
M: Monoid + 'static,
F: Foldable<'a, M::Elem, A = M::Elem> + Send,
D: Directive<Output = F> + Send,
> Directive for Fold<'a, M, D>
{
type Input = F;
type Output = M::Elem;
async fn run(self, runtime: &Runtime) -> Result<Self::Output> {
self.input.run(runtime).await?.f_fold(self.m, runtime).await
}
}
pub mod indexed_stream;
pub use indexed_stream::IndexedStream;
pub mod literal;
pub use literal::Literal;