1use std::{convert::Infallible, future::Future, marker::PhantomData};
12
13use http::status::StatusCode;
14use motore::{ServiceExt, layer::Layer, service::Service};
15
16use super::{IntoResponse, handler::Handler};
17use crate::{body::Body, context::ServerContext, request::Request, response::Response};
18
19pub mod method_router;
20pub mod router;
21mod utils;
22
23pub use self::{
24 method_router::*,
25 router::{MatchedPath, Router},
26};
27
28pub struct Route<B = Body, E = Infallible> {
30 inner: motore::service::BoxService<ServerContext, Request<B>, Response, E>,
31}
32
33impl<B, E> Route<B, E> {
34 pub fn new<S>(inner: S) -> Self
36 where
37 S: Service<ServerContext, Request<B>, Response = Response, Error = E>
38 + Send
39 + Sync
40 + 'static,
41 B: 'static,
42 {
43 Self {
44 inner: motore::service::BoxService::new(inner),
45 }
46 }
47}
48
49impl<B, E> Service<ServerContext, Request<B>> for Route<B, E> {
50 type Response = Response;
51 type Error = E;
52
53 fn call(
54 &self,
55 cx: &mut ServerContext,
56 req: Request<B>,
57 ) -> impl Future<Output = Result<Self::Response, Self::Error>> + Send {
58 self.inner.call(cx, req)
59 }
60}
61
62enum Fallback<B = Body, E = Infallible> {
63 Route(Route<B, E>),
64}
65
66impl<B, E> Service<ServerContext, Request<B>> for Fallback<B, E>
67where
68 B: Send,
69{
70 type Response = Response;
71 type Error = E;
72
73 async fn call(
74 &self,
75 cx: &mut ServerContext,
76 req: Request<B>,
77 ) -> Result<Self::Response, Self::Error> {
78 match self {
79 Self::Route(route) => route.call(cx, req).await,
80 }
81 }
82}
83
84impl<B, E> Fallback<B, E>
85where
86 B: Send + 'static,
87 E: 'static,
88{
89 fn from_status_code(status: StatusCode) -> Self {
90 Self::from_service(RouteForStatusCode::new(status))
91 }
92
93 fn from_handler<H, T>(handler: H) -> Self
94 where
95 H: Handler<T, B, E> + Clone + Send + Sync + 'static,
96 T: 'static,
97 {
98 Self::from_service(handler.into_service())
99 }
100
101 fn from_service<S>(service: S) -> Self
102 where
103 S: Service<ServerContext, Request<B>, Error = E> + Send + Sync + 'static,
104 S::Response: IntoResponse,
105 {
106 Self::Route(Route::new(
107 service.map_response(IntoResponse::into_response),
108 ))
109 }
110
111 fn map<F, B2, E2>(self, f: F) -> Fallback<B2, E2>
112 where
113 F: FnOnce(Route<B, E>) -> Route<B2, E2> + Clone + 'static,
114 {
115 match self {
116 Self::Route(route) => Fallback::Route(f(route)),
117 }
118 }
119
120 fn layer<L, B2, E2>(self, l: L) -> Fallback<B2, E2>
121 where
122 L: Layer<Route<B, E>> + Clone + Send + Sync + 'static,
123 L::Service: Service<ServerContext, Request<B2>, Error = E2> + Send + Sync + 'static,
124 <L::Service as Service<ServerContext, Request<B2>>>::Response: IntoResponse,
125 B2: 'static,
126 {
127 self.map(move |route: Route<B, E>| {
128 Route::new(
129 l.clone()
130 .layer(route)
131 .map_response(IntoResponse::into_response),
132 )
133 })
134 }
135}
136
137struct RouteForStatusCode<B, E> {
138 status: StatusCode,
139 _marker: PhantomData<fn(B, E)>,
140}
141
142impl<B, E> Clone for RouteForStatusCode<B, E> {
143 fn clone(&self) -> Self {
144 Self {
145 status: self.status,
146 _marker: self._marker,
147 }
148 }
149}
150
151impl<B, E> RouteForStatusCode<B, E> {
152 fn new(status: StatusCode) -> Self {
153 Self {
154 status,
155 _marker: PhantomData,
156 }
157 }
158}
159
160impl<B, E> Service<ServerContext, Request<B>> for RouteForStatusCode<B, E>
161where
162 B: Send,
163{
164 type Response = Response;
165 type Error = E;
166
167 async fn call(
168 &self,
169 _: &mut ServerContext,
170 _: Request<B>,
171 ) -> Result<Self::Response, Self::Error> {
172 Ok(self.status.into_response())
173 }
174}