use std::future::Future;
use super::context::Context;
use super::handler::{Handler, HandlerResult};
pub trait Layer<H> {
type Handler;
fn layer(&self, inner: H) -> Self::Handler;
}
pub trait HandlerExt<M>: Handler<M> + Sized {
fn with<L>(self, layer: L) -> L::Handler
where
L: Layer<Self>,
{
layer.layer(self)
}
}
impl<M, H> HandlerExt<M> for H where H: Handler<M> {}
#[derive(Debug, Clone, Copy, Default)]
pub struct Identity;
impl<H> Layer<H> for Identity {
type Handler = H;
fn layer(&self, inner: H) -> H {
inner
}
}
#[derive(Debug, Clone, Copy, Default)]
pub struct Stack<Inner, Outer> {
inner: Inner,
outer: Outer,
}
impl<Inner, Outer> Stack<Inner, Outer> {
#[must_use]
pub fn new(inner: Inner, outer: Outer) -> Self {
Self { inner, outer }
}
}
impl<H, Inner, Outer> Layer<H> for Stack<Inner, Outer>
where
Inner: Layer<H>,
Outer: Layer<Inner::Handler>,
{
type Handler = Outer::Handler;
fn layer(&self, inner: H) -> Self::Handler {
self.outer.layer(self.inner.layer(inner))
}
}
pub mod layers {
use tracing::{debug, info, instrument, warn};
use super::{Context, Future, Handler, HandlerResult, Layer};
#[derive(Debug, Clone, Default)]
pub struct TracingLayer {
target: Option<&'static str>,
}
impl TracingLayer {
#[must_use]
pub const fn with_target(target: &'static str) -> Self {
Self {
target: Some(target),
}
}
}
impl<H> Layer<H> for TracingLayer {
type Handler = TracingHandler<H>;
fn layer(&self, inner: H) -> Self::Handler {
TracingHandler {
inner,
target: self.target,
}
}
}
#[derive(Debug, Clone)]
pub struct TracingHandler<H> {
inner: H,
target: Option<&'static str>,
}
impl<M, H> Handler<M> for TracingHandler<H>
where
M: Sync,
H: Handler<M>,
{
#[instrument(level = "trace", skip(self, msg, ctx), fields(target = self.target))]
fn handle(&self, msg: &M, ctx: &mut Context) -> impl Future<Output = HandlerResult> + Send {
async move {
debug!(target: "ruststream::dispatch", "delivery received");
let result = self.inner.handle(msg, ctx).await;
match result {
HandlerResult::Ack => {
info!(target: "ruststream::dispatch", "handler ack");
}
HandlerResult::Nack { requeue } => {
warn!(target: "ruststream::dispatch", requeue, "handler nack");
}
}
result
}
}
}
}