pub trait Pipe<T: 'static> {
fn handle(&self, item: T, next: Box<dyn FnOnce(T) -> T>) -> T;
}
impl<T: 'static, F> Pipe<T> for F
where
F: Fn(T, Box<dyn FnOnce(T) -> T>) -> T + 'static,
{
fn handle(&self, item: T, next: Box<dyn FnOnce(T) -> T>) -> T {
(self)(item, next)
}
}
pub struct Pipeline<T: 'static> {
item: Option<T>,
pipes: Vec<Box<dyn FnOnce(T, Box<dyn FnOnce(T) -> T>) -> T>>,
}
impl<T: 'static> Pipeline<T> {
pub fn new() -> Self {
Self { item: None, pipes: Vec::new() }
}
pub fn send(mut self, item: T) -> Self {
self.item = Some(item);
self
}
pub fn through<P: Pipe<T> + 'static>(mut self, pipe: P) -> Self {
self.pipes.push(Box::new(move |item, next| pipe.handle(item, next)));
self
}
pub fn then<F>(self, destination: F) -> T
where
F: FnOnce(T) -> T + 'static,
{
let item = self.item.expect("Pipeline::then called before send");
let mut chain: Box<dyn FnOnce(T) -> T> = Box::new(destination);
for pipe in self.pipes.into_iter().rev() {
let prev = chain;
chain = Box::new(move |item| pipe(item, prev));
}
chain(item)
}
}
impl<T: 'static> Default for Pipeline<T> {
fn default() -> Self {
Self::new()
}
}