use crate::{
error::{DecodeError, DecodeResult},
packet::{FromRequest, IntoResponse, Packet, PacketComponents},
};
use std::{
collections::HashMap,
future::Future,
marker::PhantomData,
pin::Pin,
task::{ready, Context, Poll},
};
pub struct FormatA;
pub struct FormatB;
pub trait FromRequestInternal: Sized + 'static {
fn from_request(req: &Packet) -> DecodeResult<Self>;
}
impl FromRequestInternal for () {
fn from_request(_req: &Packet) -> DecodeResult<Self> {
Ok(())
}
}
impl<F: FromRequest> FromRequestInternal for F {
fn from_request(req: &Packet) -> DecodeResult<Self> {
F::from_request(req)
}
}
type BoxFuture<'a, T> = Pin<Box<dyn Future<Output = T> + Send + 'a>>;
pub trait Handler<'a, State, Format, Req, Res>: Send + Sync + 'static {
fn handle(&self, state: &'a mut State, req: Req) -> BoxFuture<'a, Res>;
}
type PacketFuture<'a> = BoxFuture<'a, Packet>;
impl<'a, State, Fun, Fut, Req, Res> Handler<'a, State, FormatA, Req, Res> for Fun
where
Fun: Fn(&'a mut State, Req) -> Fut + Send + Sync + 'static,
Fut: Future<Output = Res> + Send + 'a,
Req: FromRequest,
Res: IntoResponse,
State: Send + 'static,
{
fn handle(&self, state: &'a mut State, req: Req) -> BoxFuture<'a, Res> {
Box::pin(self(state, req))
}
}
impl<State, Fun, Fut, Req, Res> Handler<'_, State, FormatB, Req, Res> for Fun
where
Fun: Fn(Req) -> Fut + Send + Sync + 'static,
Fut: Future<Output = Res> + Send + 'static,
Req: FromRequest,
Res: IntoResponse,
State: Send + 'static,
{
fn handle(&self, _state: &mut State, req: Req) -> BoxFuture<'static, Res> {
Box::pin(self(req))
}
}
impl<'a, State, Fun, Fut, Res> Handler<'a, State, FormatA, (), Res> for Fun
where
Fun: Fn(&'a mut State) -> Fut + Send + Sync + 'static,
Fut: Future<Output = Res> + Send + 'a,
Res: IntoResponse,
State: Send + 'static,
{
fn handle(&self, state: &'a mut State, _: ()) -> BoxFuture<'a, Res> {
Box::pin(self(state))
}
}
impl<State, Fun, Fut, Res> Handler<'_, State, FormatB, (), Res> for Fun
where
Fun: Fn() -> Fut + Send + Sync + 'static,
Fut: Future<Output = Res> + Send + 'static,
Res: IntoResponse,
State: Send + 'static,
{
fn handle(&self, _state: &mut State, _: ()) -> BoxFuture<'static, Res> {
Box::pin(self())
}
}
struct HandlerFuture<'a, Res> {
fut: BoxFuture<'a, Res>,
packet: Packet,
}
impl<'a, Res> Future for HandlerFuture<'a, Res>
where
Res: IntoResponse,
{
type Output = Packet;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let this = self.get_mut();
let fut = Pin::new(&mut this.fut);
let res = ready!(fut.poll(cx));
let packet = res.into_response(&this.packet);
Poll::Ready(packet)
}
}
trait Route<S>: Send + Sync {
fn handle<'s>(&self, state: &'s mut S, packet: Packet)
-> Result<PacketFuture<'s>, HandleError>;
}
struct HandlerRoute<H, Format, Req, Res> {
handler: H,
_marker: PhantomData<fn(Format, Req) -> Res>,
}
impl<H, State, Format, Req, Res> Route<State> for HandlerRoute<H, Format, Req, Res>
where
for<'a> H: Handler<'a, State, Format, Req, Res>,
Req: FromRequestInternal,
Res: IntoResponse,
Format: 'static,
State: Send + 'static,
{
fn handle<'s>(
&self,
state: &'s mut State,
packet: Packet,
) -> Result<PacketFuture<'s>, HandleError> {
let req = match Req::from_request(&packet) {
Ok(value) => value,
Err(err) => return Err(HandleError::Decoding(err)),
};
let fut = self.handler.handle(state, req);
Ok(Box::pin(HandlerFuture { fut, packet }))
}
}
pub struct Router<C, S> {
routes: HashMap<C, Box<dyn Route<S>>>,
}
impl<C, S> Default for Router<C, S> {
fn default() -> Self {
Self {
routes: Default::default(),
}
}
}
impl<C, S> Router<C, S>
where
C: PacketComponents,
S: Send + 'static,
{
pub fn new() -> Self {
Self::default()
}
pub fn route<Format, Req, Res>(
&mut self,
component: C,
route: impl for<'a> Handler<'a, S, Format, Req, Res>,
) where
Req: FromRequestInternal,
Res: IntoResponse,
Format: 'static,
{
self.routes.insert(
component,
Box::new(HandlerRoute {
handler: route,
_marker: PhantomData,
}),
);
}
pub fn handle<'a>(
&self,
state: &'a mut S,
packet: Packet,
) -> Result<PacketFuture<'a>, HandleError> {
let target = match C::from_header(&packet.header) {
Some(value) => value,
None => return Err(HandleError::MissingHandler(packet)),
};
let route = match self.routes.get(&target) {
Some(value) => value,
None => return Err(HandleError::MissingHandler(packet)),
};
route.handle(state, packet)
}
}
#[derive(Debug)]
pub enum HandleError {
MissingHandler(Packet),
Decoding(DecodeError),
}