use std::marker::PhantomData;
use typeway_core::{Endpoint, ExtractPath, HttpMethod, PathSpec};
use crate::handler::{into_boxed_handler, BoxedHandler, Handler};
use crate::router::Router;
pub struct BoundHandler<E> {
method: http::Method,
pattern: String,
match_fn: crate::router::MatchFn,
handler: BoxedHandler,
_endpoint: PhantomData<E>,
}
impl<E> BoundHandler<E> {
pub fn new(
method: http::Method,
pattern: String,
match_fn: crate::router::MatchFn,
handler: BoxedHandler,
) -> Self {
BoundHandler {
method,
pattern,
match_fn,
handler,
_endpoint: PhantomData,
}
}
pub(crate) fn register_into(self, router: &mut Router) {
router.add_route(self.method, self.pattern, self.match_fn, self.handler);
}
}
pub fn bind<E, H, Args>(handler: H) -> BoundHandler<E>
where
E: BindableEndpoint,
H: Handler<Args>,
Args: 'static,
{
let method = E::method();
let pattern = E::pattern();
let match_fn = E::match_fn();
BoundHandler {
method,
pattern,
match_fn,
handler: into_boxed_handler(handler),
_endpoint: PhantomData,
}
}
#[macro_export]
macro_rules! bind {
($handler:expr) => {
$crate::bind::<_, _, _>($handler)
};
}
pub trait BindableEndpoint {
fn method() -> http::Method;
fn pattern() -> String;
fn match_fn() -> crate::router::MatchFn;
}
impl<M, P, Req, Res, Q, Err> BindableEndpoint for Endpoint<M, P, Req, Res, Q, Err>
where
M: HttpMethod,
P: PathSpec + ExtractPath + Send + 'static,
P::Captures: Send,
{
fn method() -> http::Method {
M::METHOD
}
fn pattern() -> String {
P::pattern()
}
fn match_fn() -> crate::router::MatchFn {
Box::new(|segments| P::extract(segments).is_some())
}
}