1use core::{future::Future, marker::PhantomData};
10use http_kit::{Endpoint, Request, Response};
11use skyzen_core::{Extractor, Responder};
12use std::fmt::Display;
13
14pub enum HandlerError<E: Extractor, R: Responder> {
16 ExtractorError(E::Error),
18 ResponderError(R::Error),
20}
21
22impl<E: Extractor, R: Responder> Display for HandlerError<E, R> {
23 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
24 match self {
25 Self::ExtractorError(e) => write!(f, "{e}"),
26 Self::ResponderError(e) => write!(f, "{e}"),
27 }
28 }
29}
30
31impl<E: Extractor, R: Responder> core::fmt::Debug for HandlerError<E, R> {
32 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
33 match self {
34 Self::ExtractorError(e) => write!(f, "{e:?}"),
35 Self::ResponderError(e) => write!(f, "{e:?}"),
36 }
37 }
38}
39
40impl<E: Extractor, R: Responder> http_kit::HttpError for HandlerError<E, R> {
41 fn status(&self) -> http_kit::StatusCode {
42 match self {
43 Self::ExtractorError(e) => e.status(),
44 Self::ResponderError(e) => e.status(),
45 }
46 }
47}
48
49impl<E: Extractor, R: Responder> core::error::Error for HandlerError<E, R> {}
50
51pub trait Handler<T: Extractor, R: Responder>: Send + Sync + Clone + 'static {
54 fn call_handler(
56 &self,
57 request: &mut Request,
58 ) -> impl Future<Output = Result<Response, HandlerError<T, R>>> + Send;
59}
60
61#[derive(Debug)]
63pub struct IntoEndpoint<H: Handler<T, R>, T: Extractor, R: Responder> {
64 handler: H,
65 _marker: PhantomData<(T, R)>,
66}
67
68pub const fn into_endpoint<T: Extractor + Send, R: Responder, H: Handler<T, R>>(
70 handler: H,
71) -> IntoEndpoint<H, T, R> {
72 IntoEndpoint::new(handler)
73}
74
75impl<H: Handler<T, R>, T: Extractor, R: Responder> IntoEndpoint<H, T, R> {
76 pub const fn new(handler: H) -> Self {
78 Self {
79 handler,
80 _marker: PhantomData,
81 }
82 }
83}
84
85impl<H, T, R> Clone for IntoEndpoint<H, T, R>
86where
87 H: Handler<T, R> + Clone,
88 T: Extractor,
89 R: Responder,
90{
91 fn clone(&self) -> Self {
92 Self {
93 handler: self.handler.clone(),
94 _marker: PhantomData,
95 }
96 }
97}
98
99macro_rules! impl_handler {
100 ($($ty:ident),*) => {
101 #[allow(non_snake_case)]
102
103 impl<F, Fut, Res,$($ty:Extractor,)*> Handler<($($ty,)*) , Res> for F
104 where
105 F: 'static + Clone + Send + Sync + Fn($($ty,)*) -> Fut,
106 Fut: Send + Future<Output = Res>,
107 Res: Responder,
108 {
109 async fn call_handler(&self, request: &mut Request) -> Result<Response, HandlerError<($($ty,)*), Res>> {
110 let ($($ty,)*) = <($($ty,)*) as Extractor>::extract(request).await.map_err(|e| HandlerError::ExtractorError(e))?;
111 let mut response = Response::new(http_kit::Body::empty());
112 (self)($($ty,)*).await.respond_to(request,&mut response).map_err(|e| HandlerError::ResponderError(e))?;
113 Ok(response)
114 }
115 }
116 };
117}
118
119tuples!(impl_handler);
120
121impl<H: Handler<T, R> + Send + Sync, T: Extractor + Send + Sync, R: Responder + Send + Sync>
122 Endpoint for IntoEndpoint<H, T, R>
123{
124 type Error = HandlerError<T, R>;
125 async fn respond(&mut self, request: &mut Request) -> Result<Response, Self::Error> {
126 self.handler.call_handler(request).await
127 }
128}