use std::sync::Arc;
use std::future::Future;
use std::pin::Pin;
pub struct ChainGeneric<T> {
links: Vec<Arc<dyn Fn(T) -> Pin<Box<dyn Future<Output = T> + Send>> + Send + Sync>>,
middleware: Vec<Arc<dyn crate::middleware::Middleware<T>>>,
pub branches: Vec<Branch<T>>,
}
pub struct Branch<T> {
pub source: usize,
pub target: usize,
pub condition: Arc<dyn Fn(&T) -> bool + Send + Sync>,
}
impl<T: 'static + Send> ChainGeneric<T> {
pub fn new() -> Self {
ChainGeneric { links: Vec::new(), middleware: Vec::new(), branches: Vec::new() }
}
pub fn add_link(&mut self, link: Arc<dyn Fn(T) -> Pin<Box<dyn Future<Output = T> + Send>> + Send + Sync>) {
self.links.push(link);
}
pub fn use_middleware(&mut self, mw: Arc<dyn crate::middleware::Middleware<T>>) {
self.middleware.push(mw);
}
pub fn link_count(&self) -> usize {
self.links.len()
}
pub fn connect<F>(&mut self, source: usize, target: usize, condition: F)
where
F: Fn(&T) -> bool + Send + Sync + 'static,
{
self.branches.push(Branch {
source,
target,
condition: Arc::new(condition),
});
}
pub async fn run(&self, ctx: T) -> T {
let mut idx = 0;
let mut ctx = ctx;
while idx < self.links.len() {
for mw in &self.middleware {
mw.before(&ctx).await;
}
ctx = (self.links[idx].clone())(ctx).await;
for mw in &self.middleware {
mw.after(&ctx).await;
}
if let Some(branch) = self.branches.iter().find(|b| b.source == idx && (b.condition)(&ctx)) {
idx = branch.target;
} else {
idx += 1;
}
}
ctx
}
}
pub type Chain = ChainGeneric<crate::context::Context>;
pub type LinkGeneric<C> = crate::links::LinkGeneric<C>;
pub type Link = crate::links::Link;