cat_dev/net/server/
request_handlers.rs

1use crate::{
2	errors::CatBridgeError,
3	net::models::{FromRequest, FromRequestParts, IntoResponse, Request, Response},
4};
5use std::{
6	marker::PhantomData,
7	pin::Pin,
8	task::{Context, Poll},
9};
10use tower::Service;
11
12/// A route handler, attempts to be an incredibly thin layer between a
13/// function, and the actual ending handler.
14///
15/// Implemented so we can implement for function that accepts any varying
16/// amount of args of types that implement from request parts.
17///
18/// `ParamTy` is kept to prevent generation of conflicting type implementations
19/// of this trait. It however is not actually needed by any of our code.
20pub trait Handler<ParamTy, State: Clone + Send + Sync + 'static> {
21	type Future: Future<Output = Result<Response, CatBridgeError>> + Send + 'static;
22
23	fn call(self, req: Request<State>) -> Self::Future;
24}
25
26/// Allow any async function without arguments to be a handler
27impl<UnderlyingFnType, FnFutureTy, ResponseTy, State: Clone + Send + Sync + 'static>
28	Handler<(), State> for UnderlyingFnType
29where
30	UnderlyingFnType: FnOnce() -> FnFutureTy + Clone + Send + 'static,
31	FnFutureTy: Future<Output = ResponseTy> + Send,
32	ResponseTy: IntoResponse,
33{
34	type Future = Pin<Box<dyn Future<Output = Result<Response, CatBridgeError>> + Send>>;
35
36	fn call(self, _req: Request<State>) -> Self::Future {
37		Box::pin(async move { self().await.to_response() })
38	}
39}
40
41macro_rules! fn_to_handler {
42	(
43		[$($ty:ident),*], $last:ident
44	) => {
45		#[allow(non_snake_case, unused_mut)]
46		impl<UnderlyingFnType, FnFutureTy, OutputTy, State: Clone + Send + Sync + 'static, $($ty,)* $last> Handler<($($ty,)* $last,), State> for UnderlyingFnType
47		where
48			UnderlyingFnType: FnOnce($($ty,)* $last) -> FnFutureTy + Clone + Send + 'static,
49			FnFutureTy: Future<Output = OutputTy> + Send,
50			OutputTy: IntoResponse,
51			$( $ty: FromRequestParts<State> + Send, )*
52			$last: FromRequest<State> + Send,
53		{
54			type Future = Pin<Box<dyn Future<Output = Result<Response, CatBridgeError>> + Send>>;
55
56			fn call(self, mut req: Request<State>) -> Self::Future {
57				Box::pin(async move {
58					$(
59						let $ty = $ty::from_request_parts(&mut req).await?;
60					)*
61					let $last = $last::from_request(req).await?;
62					let res = self($($ty,)* $last).await;
63					res.to_response()
64				})
65			}
66		}
67	}
68}
69
70fn_to_handler!([], T1);
71fn_to_handler!([T1], T2);
72fn_to_handler!([T1, T2], T3);
73fn_to_handler!([T1, T2, T3], T4);
74fn_to_handler!([T1, T2, T3, T4], T5);
75fn_to_handler!([T1, T2, T3, T4, T5], T6);
76fn_to_handler!([T1, T2, T3, T4, T5, T6], T7);
77fn_to_handler!([T1, T2, T3, T4, T5, T6, T7], T8);
78fn_to_handler!([T1, T2, T3, T4, T5, T6, T7, T8], T9);
79fn_to_handler!([T1, T2, T3, T4, T5, T6, T7, T8, T9], T10);
80fn_to_handler!([T1, T2, T3, T4, T5, T6, T7, T8, T9, T10], T11);
81fn_to_handler!([T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11], T12);
82fn_to_handler!([T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12], T13);
83fn_to_handler!(
84	[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13],
85	T14
86);
87fn_to_handler!(
88	[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14],
89	T15
90);
91fn_to_handler!(
92	[
93		T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15
94	],
95	T16
96);
97
98/// A wrapper around a handler to implement a service.
99pub struct HandlerAsService<HandlerTy, HandlerParamsTy> {
100	handler: HandlerTy,
101	marker: PhantomData<HandlerParamsTy>,
102}
103
104impl<HandlerTy, HandlerParamsTy> HandlerAsService<HandlerTy, HandlerParamsTy> {
105	#[must_use]
106	pub(crate) fn new(handler: HandlerTy) -> Self {
107		Self {
108			handler,
109			marker: PhantomData,
110		}
111	}
112}
113
114impl<HandlerTy, HandlerParamsTy> Clone for HandlerAsService<HandlerTy, HandlerParamsTy>
115where
116	HandlerTy: Clone,
117{
118	fn clone(&self) -> Self {
119		Self {
120			handler: self.handler.clone(),
121			marker: PhantomData,
122		}
123	}
124}
125
126impl<HandlerTy, HandlerParamsTy, State: Clone + Send + Sync + 'static> Service<Request<State>>
127	for HandlerAsService<HandlerTy, HandlerParamsTy>
128where
129	HandlerTy: Handler<HandlerParamsTy, State> + Clone + Send + 'static,
130{
131	type Response = Response;
132	type Error = CatBridgeError;
133	type Future = HandlerTy::Future;
134
135	#[inline]
136	fn poll_ready(&mut self, _ctx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
137		Poll::Ready(Ok(()))
138	}
139
140	fn call(&mut self, req: Request<State>) -> Self::Future {
141		let handler = self.handler.clone();
142		handler.call(req)
143	}
144}