use crate::{async_trait, Conn, Info, Status, Upgrade};
use std::{borrow::Cow, future::Future, sync::Arc};
#[async_trait]
pub trait Handler: Send + Sync + 'static {
async fn run(&self, conn: Conn) -> Conn;
async fn init(&mut self, _info: &mut Info) {}
async fn before_send(&self, conn: Conn) -> Conn {
conn
}
fn has_upgrade(&self, _upgrade: &Upgrade) -> bool {
false
}
async fn upgrade(&self, _upgrade: Upgrade) {
unimplemented!("if has_upgrade returns true, you must also implement upgrade")
}
fn name(&self) -> Cow<'static, str> {
std::any::type_name::<Self>().into()
}
}
#[async_trait]
impl Handler for Box<dyn Handler> {
async fn run(&self, conn: Conn) -> Conn {
self.as_ref().run(conn).await
}
async fn init(&mut self, info: &mut Info) {
self.as_mut().init(info).await;
}
async fn before_send(&self, conn: Conn) -> Conn {
self.as_ref().before_send(conn).await
}
fn name(&self) -> Cow<'static, str> {
self.as_ref().name()
}
fn has_upgrade(&self, upgrade: &Upgrade) -> bool {
self.as_ref().has_upgrade(upgrade)
}
async fn upgrade(&self, upgrade: Upgrade) {
self.as_ref().upgrade(upgrade).await;
}
}
#[async_trait]
impl Handler for Status {
async fn run(&self, conn: Conn) -> Conn {
conn.with_status(*self)
}
}
impl std::fmt::Debug for Box<dyn Handler> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(self.name().as_ref())
}
}
#[async_trait]
impl<H: Handler> Handler for Arc<H> {
async fn run(&self, conn: Conn) -> Conn {
self.as_ref().run(conn).await
}
async fn init(&mut self, info: &mut Info) {
Self::get_mut(self)
.expect("cannot call init when there are already clones of an Arc<Handler>")
.init(info)
.await;
}
async fn before_send(&self, conn: Conn) -> Conn {
self.as_ref().before_send(conn).await
}
fn name(&self) -> Cow<'static, str> {
self.as_ref().name()
}
fn has_upgrade(&self, upgrade: &Upgrade) -> bool {
self.as_ref().has_upgrade(upgrade)
}
async fn upgrade(&self, upgrade: Upgrade) {
self.as_ref().upgrade(upgrade).await;
}
}
#[async_trait]
impl<H: Handler> Handler for Vec<H> {
async fn run(&self, mut conn: Conn) -> Conn {
for handler in self {
log::debug!("running {}", handler.name());
conn = handler.run(conn).await;
if conn.is_halted() {
break;
}
}
conn
}
async fn init(&mut self, info: &mut Info) {
for handler in self {
handler.init(info).await;
}
}
async fn before_send(&self, mut conn: Conn) -> Conn {
for handler in self.iter().rev() {
conn = handler.before_send(conn).await;
}
conn
}
fn name(&self) -> Cow<'static, str> {
self.iter()
.map(Handler::name)
.collect::<Vec<_>>()
.join(",")
.into()
}
fn has_upgrade(&self, upgrade: &Upgrade) -> bool {
self.iter().any(|g| g.has_upgrade(upgrade))
}
async fn upgrade(&self, upgrade: Upgrade) {
if let Some(handler) = self.iter().find(|g| g.has_upgrade(&upgrade)) {
handler.upgrade(upgrade).await;
}
}
}
#[async_trait]
impl<Fun, Fut> Handler for Fun
where
Fun: Fn(Conn) -> Fut + Send + Sync + 'static,
Fut: Future<Output = Conn> + Send + 'static,
{
async fn run(&self, conn: Conn) -> Conn {
(self)(conn).await
}
}
#[async_trait]
impl Handler for &'static str {
async fn run(&self, conn: Conn) -> Conn {
conn.ok(*self)
}
fn name(&self) -> Cow<'static, str> {
format!("conn.ok({:?})", &self).into()
}
}
#[async_trait]
impl Handler for () {
async fn run(&self, conn: Conn) -> Conn {
conn
}
}
#[async_trait]
impl<H: Handler> Handler for Option<H> {
async fn run(&self, conn: Conn) -> Conn {
let handler = crate::conn_unwrap!(self, conn);
handler.run(conn).await
}
async fn init(&mut self, info: &mut Info) {
if let Some(handler) = self {
handler.init(info).await;
}
}
async fn before_send(&self, conn: Conn) -> Conn {
let handler = crate::conn_unwrap!(self, conn);
handler.before_send(conn).await
}
fn name(&self) -> Cow<'static, str> {
match self {
Some(h) => h.name(),
None => "-".into(),
}
}
fn has_upgrade(&self, upgrade: &Upgrade) -> bool {
match self {
Some(h) => h.has_upgrade(upgrade),
None => false,
}
}
async fn upgrade(&self, upgrade: Upgrade) {
if let Some(handler) = self {
handler.upgrade(upgrade).await;
}
}
}
macro_rules! reverse_before_send {
($conn:ident, $name:ident) => (
let $conn = ($name).before_send($conn).await;
);
($conn:ident, $name:ident $($other_names:ident)+) => (
reverse_before_send!($conn, $($other_names)*);
reverse_before_send!($conn, $name);
);
}
macro_rules! impl_handler_tuple {
($($name:ident)+) => (
#[async_trait]
impl<$($name),*> Handler for ($($name,)*) where $($name: Handler),* {
#[allow(non_snake_case)]
async fn run(&self, conn: Conn) -> Conn {
let ($(ref $name,)*) = *self;
$(
log::debug!("running {}", ($name).name());
let conn = ($name).run(conn).await;
if conn.is_halted() { return conn }
)*
conn
}
#[allow(non_snake_case)]
async fn init(&mut self, info: &mut Info) {
let ($(ref mut $name,)*) = *self;
$(
log::trace!("initializing {}", ($name).name());
($name).init(info).await;
)*
}
#[allow(non_snake_case)]
async fn before_send(&self, conn: Conn) -> Conn {
let ($(ref $name,)*) = *self;
reverse_before_send!(conn, $($name)+);
conn
}
#[allow(non_snake_case)]
fn has_upgrade(&self, upgrade: &Upgrade) -> bool {
let ($(ref $name,)*) = *self;
$(if ($name).has_upgrade(upgrade) { return true })*
false
}
#[allow(non_snake_case)]
async fn upgrade(&self, upgrade: Upgrade) {
let ($(ref $name,)*) = *self;
$(if ($name).has_upgrade(&upgrade) {
return ($name).upgrade(upgrade).await;
})*
}
#[allow(non_snake_case)]
fn name(&self) -> Cow<'static, str> {
let ($(ref $name,)*) = *self;
format!(concat!("(\n", $(
concat!(" {",stringify!($name) ,":},\n")
),*, ")"), $($name = ($name).name()),*).into()
}
}
);
}
impl_handler_tuple! { A B }
impl_handler_tuple! { A B C }
impl_handler_tuple! { A B C D }
impl_handler_tuple! { A B C D E }
impl_handler_tuple! { A B C D E F }
impl_handler_tuple! { A B C D E F G }
impl_handler_tuple! { A B C D E F G H }
impl_handler_tuple! { A B C D E F G H I }
impl_handler_tuple! { A B C D E F G H I J }
impl_handler_tuple! { A B C D E F G H I J K }
impl_handler_tuple! { A B C D E F G H I J K L }
impl_handler_tuple! { A B C D E F G H I J K L M }
impl_handler_tuple! { A B C D E F G H I J K L M N }
impl_handler_tuple! { A B C D E F G H I J K L M N O }