use crate::BoxFuture;
use std::sync::Arc;
type Step<'p, I, O, C, E> = dyn Fn(I, &C) -> Result<O, E> + Send + Sync + 'p;
pub struct Pipeline<'p, I, O, C, E> {
step: Arc<Step<'p, I, O, C, E>>,
}
impl<I, O, C, E> Clone for Pipeline<'_, I, O, C, E> {
fn clone(&self) -> Self {
Self {
step: self.step.clone(),
}
}
}
impl<'p, I: 'p, O: 'p, C: 'p, E: 'p> Pipeline<'p, I, O, C, E> {
pub fn plain(f: impl Fn(I, &C) -> Result<O, E> + Send + Sync + 'p) -> Self {
Self { step: Arc::new(f) }
}
pub fn run(&self, input: I, context: &C) -> Result<O, E> {
(self.step)(input, context)
}
pub fn then<N: 'p>(
self,
f: impl Fn(O, &C) -> Result<N, E> + Send + Sync + 'p,
) -> Pipeline<'p, I, N, C, E> {
Pipeline::plain(move |input, context| f(self.run(input, context)?, context))
}
pub fn check(self, f: impl Fn(&O, &C) -> Result<(), E> + Send + Sync + 'p) -> Self {
self.then(move |value, context| {
f(&value, context)?;
Ok(value)
})
}
pub fn wrap(
self,
f: impl Fn(I, &C, &dyn Fn(I, &C) -> Result<O, E>) -> Result<O, E> + Send + Sync + 'p,
) -> Self {
Self::plain(move |input, context| {
f(input, context, &|value, context| self.run(value, context))
})
}
}
type AsyncStep<I, O, C, E> = dyn for<'a> Fn(I, &'a C) -> BoxFuture<'a, Result<O, E>> + Send + Sync;
pub struct AsyncPipeline<I, O, C, E> {
step: Arc<AsyncStep<I, O, C, E>>,
}
impl<I, O, C, E> Clone for AsyncPipeline<I, O, C, E> {
fn clone(&self) -> Self {
Self {
step: self.step.clone(),
}
}
}
impl<I: Send + 'static, O: Send + 'static, C: Sync + 'static, E: Send + 'static>
AsyncPipeline<I, O, C, E>
{
pub fn plain(
f: impl for<'a> Fn(I, &'a C) -> BoxFuture<'a, Result<O, E>> + Send + Sync + 'static,
) -> Self {
Self { step: Arc::new(f) }
}
pub fn run<'a>(&'a self, input: I, context: &'a C) -> BoxFuture<'a, Result<O, E>> {
let step = self.step.clone();
Box::pin(async move { step(input, context).await })
}
pub fn then<N: Send + 'static>(
self,
f: impl for<'a> Fn(O, &'a C) -> BoxFuture<'a, Result<N, E>> + Send + Sync + 'static,
) -> AsyncPipeline<I, N, C, E> {
let f = Arc::new(f);
AsyncPipeline::plain(move |input, context| {
let previous = self.clone();
let f = f.clone();
Box::pin(async move { f(previous.run(input, context).await?, context).await })
})
}
pub fn check(
self,
f: impl for<'a> Fn(&'a O, &'a C) -> BoxFuture<'a, Result<(), E>> + Send + Sync + 'static,
) -> Self
where
O: Sync,
{
let f = Arc::new(f);
self.then(move |value, context| {
let f = f.clone();
Box::pin(async move {
f(&value, context).await?;
Ok(value)
})
})
}
pub fn wrap(
self,
f: impl for<'a> Fn(I, &'a C, &'a Self) -> BoxFuture<'a, Result<O, E>> + Send + Sync + 'static,
) -> Self {
let f = Arc::new(f);
Self::plain(move |input, context| {
let previous = self.clone();
let f = f.clone();
Box::pin(async move { f(input, context, &previous).await })
})
}
}