#![forbid(unsafe_code, rust_2018_idioms)]
#![deny(missing_debug_implementations, nonstandard_style)]
#![warn(missing_docs, rustdoc::missing_doc_code_examples, unreachable_pub)]
pub type BoxFuture<'a, Output> =
std::pin::Pin<Box<dyn 'a + Send + std::future::Future<Output = Output>>>;
pub trait Handle<'a, Context>
where
Self: Send + Sync + 'static,
{
type Output;
#[must_use]
fn call(&'a self, cx: &'a mut Context) -> BoxFuture<'a, Self::Output>;
}
impl<'a, Context, Output, F, Fut> Handle<'a, Context> for F
where
F: Send + Sync + 'static + Fn(&'a mut Context) -> Fut,
Fut: std::future::Future<Output = Output> + Send + 'a,
Context: 'a,
{
type Output = Output;
#[must_use]
fn call(&'a self, cx: &'a mut Context) -> BoxFuture<'a, Self::Output> {
Box::pin((self)(cx))
}
}
#[cfg(test)]
#[allow(clippy::unit_cmp)]
mod tests {
use crate::{BoxFuture, Handle};
use anyhow::Error;
use futures::executor::block_on;
use std::{future::Future, sync::Arc};
type Result = anyhow::Result<()>;
type Middleware = dyn for<'a> Handle<'a, Context, Output = Result>;
struct Context {
index: usize,
middleware: Vec<Arc<Middleware>>,
}
impl Context {
async fn next(&mut self) -> Result {
if let Some(m) = self.middleware.pop() {
m.call(self).await
} else {
Ok(())
}
}
}
async fn a(cx: &mut Context) -> Result {
let size = cx.middleware.len();
let repeat = "-".repeat(2 * size);
println!("exec Fn a --{}>> {:>2}", repeat, cx.index);
assert_eq!(cx.index, 0);
cx.index += 1;
assert_eq!(cx.index, 1);
let fut = cx.next().await;
assert_eq!(cx.index, 1);
cx.index -= 1;
assert_eq!(cx.index, 0);
println!("exec Fn a --{}<< {:>2}", repeat, cx.index);
fut
}
#[allow(clippy::needless_lifetimes)]
fn b<'a>(cx: &'a mut Context) -> BoxFuture<'a, Result> {
let size = cx.middleware.len();
let repeat = "-".repeat(2 * size);
println!("exec Fn b --{}>> {:>2}", repeat, cx.index);
assert_eq!(cx.index, 1);
cx.index += 1;
assert_eq!(cx.index, 2);
Box::pin(async move {
let fut = cx.next().await;
assert_eq!(cx.index, 2);
cx.index -= 1;
assert_eq!(cx.index, 1);
println!("exec Fn b --{}<< {:>2}", repeat, cx.index);
fut
})
}
fn c(cx: &mut Context) -> BoxFuture<'_, Result> {
let size = cx.middleware.len();
let repeat = "-".repeat(2 * size);
println!("exec Fn c --{}>> {:>2}", repeat, cx.index);
assert_eq!(cx.index, 2);
cx.index += 1;
assert_eq!(cx.index, 3);
Box::pin(async move {
let fut = cx.next().await;
assert_eq!(cx.index, 3);
cx.index -= 1;
assert_eq!(cx.index, 2);
println!("exec Fn c --{}<< {:>2}", repeat, cx.index);
fut
})
}
#[allow(clippy::needless_lifetimes)]
fn d<'a>(cx: &'a mut Context) -> impl Future<Output = Result> + 'a {
let size = cx.middleware.len();
let repeat = "-".repeat(2 * size);
println!("exec Fn d --{}>> {:>2}", repeat, cx.index);
assert_eq!(cx.index, 3);
cx.index += 1;
assert_eq!(cx.index, 4);
async move {
let fut = cx.next().await;
assert_eq!(cx.index, 4);
cx.index -= 1;
assert_eq!(cx.index, 3);
println!("exec Fn d --{}<< {:>2}", repeat, cx.index);
fut
}
}
fn e(cx: &mut Context) -> impl Future<Output = Result> + '_ {
let size = cx.middleware.len();
let repeat = "-".repeat(2 * size);
println!("exec Fn e --{}>> {:>2}", repeat, cx.index);
assert_eq!(cx.index, 4);
cx.index += 1;
assert_eq!(cx.index, 5);
async move {
let fut = cx.next().await;
assert_eq!(cx.index, 5);
cx.index -= 1;
assert_eq!(cx.index, 4);
println!("exec Fn e --{}<< {:>2}", repeat, cx.index);
fut
}
}
async fn f(cx: &mut Context) -> Result {
let size = cx.middleware.len();
let repeat = "-".repeat(2 * size);
println!("exec Fn f --{}>> {:>2}", repeat, cx.index);
assert_eq!(cx.index, 5);
cx.index += 1;
assert_eq!(cx.index, 6);
let fut = cx.next().await;
assert_eq!(cx.index, 6);
cx.index -= 1;
assert_eq!(cx.index, 5);
println!("exec Fn f --{}<< {:>2}", repeat, cx.index);
fut
}
#[derive(Clone)]
struct A {
index: usize,
}
impl<'a> Handle<'a, Context> for A {
type Output = Result;
fn call(&'a self, cx: &'a mut Context) -> BoxFuture<'a, Self::Output> {
Box::pin(async move {
let size = cx.middleware.len();
let repeat = "-".repeat(2 * size);
println!("exec St A --{}>> {:>2}", repeat, cx.index);
assert_eq!(cx.index, 6);
cx.index += self.index; assert_eq!(cx.index, 7);
let fut = cx.next().await;
assert_eq!(cx.index, 7);
cx.index -= self.index; assert_eq!(cx.index, 6);
println!("exec St A --{}<< {:>2}", repeat, cx.index);
fut
})
}
}
struct B {
index: usize,
}
impl<'a> Handle<'a, Context> for B {
type Output = Result;
fn call(&'a self, cx: &'a mut Context) -> BoxFuture<'a, Self::Output> {
Box::pin(async move {
let size = cx.middleware.len();
let repeat = "-".repeat(2 * size);
println!("exec St B --{}>> {:>2}", repeat, cx.index);
assert_eq!(cx.index, 7);
cx.index += self.index; assert_eq!(cx.index, 9);
let fut = cx.next().await;
assert_eq!(cx.index, 9);
cx.index -= self.index; assert_eq!(cx.index, 7);
println!("exec St B --{}<< {:>2}", repeat, cx.index);
fut
})
}
}
struct C {
index: usize,
}
impl<'a> Handle<'a, Context> for C {
type Output = Result;
fn call(&'a self, cx: &'a mut Context) -> BoxFuture<'a, Self::Output> {
Box::pin(async move {
let size = cx.middleware.len();
let repeat = "-".repeat(2 * size);
println!("exec St C --{}>> {:>2}", repeat, cx.index);
assert_eq!(cx.index, 9);
cx.index += self.index; assert_eq!(cx.index, 12);
let fut = cx.next().await;
assert_eq!(cx.index, 12);
cx.index -= self.index; assert_eq!(cx.index, 9);
println!("exec St C --{}<< {:>2}", repeat, cx.index);
fut
})
}
}
#[test]
fn futures_rt() {
assert!(block_on(async move {
let mut cx = Context {
index: 0,
middleware: Vec::new(),
};
let mut v: Vec<Box<Middleware>> = vec![
Box::new(f),
Box::new(e),
Box::new(d),
Box::new(c),
Box::new(b),
Box::new(a),
Box::new(A { index: 1 }),
Box::new(B { index: 2 }),
Box::new(C { index: 3 }),
];
v.reverse();
assert_eq!(v.len(), 9);
let mut v: Vec<Arc<Middleware>> = vec![];
v.push(Arc::new(|cx: &mut Context| {
assert_eq!(cx.index, 12);
println!("We handled it!");
async move {
Ok(())
}
}));
v.push(Arc::new(C { index: 3 }));
v.push(Arc::new(B { index: 2 }));
v.push(Arc::new(A { index: 1 }));
v.push(Arc::new(f));
v.push(Arc::new(e));
v.push(Arc::new(d));
v.push(Arc::new(c));
v.push(Arc::new(b));
v.push(Arc::new(a));
cx.middleware = v.clone();
println!("mw 0: {}", v.len());
let result = cx.next().await?;
assert_eq!(result, ());
println!("mw 1: {}", v.len());
cx.middleware = v.clone();
let result = cx.next().await?;
assert_eq!(result, ());
println!("mw 2: {}", v.len());
cx.middleware = v.clone();
let result = cx.next().await?;
assert_eq!(result, ());
Ok::<_, Error>(())
})
.is_ok());
}
#[async_std::test]
async fn async_std_rt() -> Result {
let mut cx = Context {
index: 0,
middleware: Vec::new(),
};
let mut v: Vec<Arc<Middleware>> = vec![];
v.insert(0, Arc::new(a));
v.insert(0, Arc::new(b));
v.insert(0, Arc::new(c));
v.insert(0, Arc::new(d));
v.insert(0, Arc::new(e));
v.insert(0, Arc::new(f));
v.insert(0, Arc::new(A { index: 1 }));
v.insert(0, Arc::new(B { index: 2 }));
v.insert(0, Arc::new(C { index: 3 }));
async fn handler(cx: &mut Context) -> Result {
assert_eq!(cx.index, 12);
println!("We handled it!");
Ok(())
}
v.insert(0, Arc::new(handler));
cx.middleware = v.clone();
println!("mw 0: {}", v.len());
let result = cx.next().await?;
assert_eq!(result, ());
println!("mw 1: {}", v.len());
cx.middleware = v.clone();
let result = cx.next().await?;
assert_eq!(result, ());
println!("mw 2: {}", v.len());
cx.middleware = v.clone();
let result = cx.next().await?;
assert_eq!(result, ());
Ok(())
}
}