Skip to main content

lexa_framework/routing/
router.rs

1// ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
2// ┃ Copyright: (c) 2023, Mike 'PhiSyX' S. (https://github.com/PhiSyX)         ┃
3// ┃ SPDX-License-Identifier: MPL-2.0                                          ┃
4// ┃ ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ ┃
5// ┃                                                                           ┃
6// ┃  This Source Code Form is subject to the terms of the Mozilla Public      ┃
7// ┃  License, v. 2.0. If a copy of the MPL was not distributed with this      ┃
8// ┃  file, You can obtain one at https://mozilla.org/MPL/2.0/.                ┃
9// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
10
11use core::fmt;
12use std::collections::HashSet;
13
14use super::collection::RouteCollection;
15use crate::state;
16
17// --------- //
18// Structure //
19// --------- //
20
21pub struct Router<UserState> {
22	pub name: String,
23	pub fullpath: String,
24	pub methods: HashSet<axum::http::Method>,
25	pub action: Option<axum::routing::MethodRouter<state::State<UserState>>>,
26}
27
28// -------------- //
29// Implémentation //
30// -------------- //
31
32impl<US> Router<US> {
33	pub fn path(path: impl ToString + fmt::Debug) -> Self {
34		let name = format!("{path:?}");
35		Self {
36			name,
37			fullpath: path.to_string(),
38			action: Default::default(),
39			methods: Default::default(),
40		}
41	}
42
43	pub fn any<Action, ActionType>(mut self, action: Action) -> Self
44	where
45		Action: axum::handler::Handler<ActionType, state::State<US>>,
46		ActionType: 'static,
47		US: 'static,
48		US: Clone,
49		US: Send + Sync,
50	{
51		self.action.replace(axum::routing::any(action));
52		self.methods.extend([
53			axum::http::Method::DELETE,
54			axum::http::Method::GET,
55			axum::http::Method::HEAD,
56			axum::http::Method::OPTIONS,
57			axum::http::Method::PATCH,
58			axum::http::Method::POST,
59			axum::http::Method::PUT,
60			axum::http::Method::TRACE,
61		]);
62		self
63	}
64
65	pub fn delete<Action, ActionType>(mut self, action: Action) -> Self
66	where
67		Action: axum::handler::Handler<ActionType, state::State<US>>,
68		ActionType: 'static,
69		US: 'static,
70		US: Clone,
71		US: Send + Sync,
72	{
73		if let Some(current_action) = self.action.take() {
74			self.action.replace(current_action.delete(action));
75		} else {
76			self.action.replace(axum::routing::delete(action));
77		}
78		self.methods.insert(axum::http::Method::DELETE);
79		self
80	}
81
82	pub fn get<Action, ActionType>(mut self, action: Action) -> Self
83	where
84		Action: axum::handler::Handler<ActionType, state::State<US>>,
85		ActionType: 'static,
86		US: 'static,
87		US: Clone,
88		US: Send + Sync,
89	{
90		if let Some(current_action) = self.action.take() {
91			self.action.replace(current_action.get(action));
92		} else {
93			self.action.replace(axum::routing::get(action));
94		}
95		self.methods.insert(axum::http::Method::GET);
96		self
97	}
98
99	pub fn head<Action, ActionType>(mut self, action: Action) -> Self
100	where
101		Action: axum::handler::Handler<ActionType, state::State<US>>,
102		ActionType: 'static,
103		US: 'static,
104		US: Clone,
105		US: Send + Sync,
106	{
107		if let Some(current_action) = self.action.take() {
108			self.action.replace(current_action.head(action));
109		} else {
110			self.action.replace(axum::routing::head(action));
111		}
112		self.methods.insert(axum::http::Method::HEAD);
113		self
114	}
115
116	pub fn options<Action, ActionType>(mut self, action: Action) -> Self
117	where
118		Action: axum::handler::Handler<ActionType, state::State<US>>,
119		ActionType: 'static,
120		US: 'static,
121		US: Clone,
122		US: Send + Sync,
123	{
124		if let Some(current_action) = self.action.take() {
125			self.action.replace(current_action.options(action));
126		} else {
127			self.action.replace(axum::routing::options(action));
128		}
129		self.methods.insert(axum::http::Method::OPTIONS);
130		self
131	}
132
133	pub fn patch<Action, ActionType>(mut self, action: Action) -> Self
134	where
135		Action: axum::handler::Handler<ActionType, state::State<US>>,
136		ActionType: 'static,
137		US: 'static,
138		US: Clone,
139		US: Send + Sync,
140	{
141		if let Some(current_action) = self.action.take() {
142			self.action.replace(current_action.patch(action));
143		} else {
144			self.action.replace(axum::routing::patch(action));
145		}
146		self.methods.insert(axum::http::Method::PATCH);
147		self
148	}
149
150	pub fn post<Action, ActionType>(mut self, action: Action) -> Self
151	where
152		Action: axum::handler::Handler<ActionType, state::State<US>>,
153		ActionType: 'static,
154		US: 'static,
155		US: Clone,
156		US: Send + Sync,
157	{
158		if let Some(current_action) = self.action.take() {
159			self.action.replace(current_action.post(action));
160		} else {
161			self.action.replace(axum::routing::post(action));
162		}
163		self.methods.insert(axum::http::Method::POST);
164		self
165	}
166
167	pub fn put<Action, ActionType>(mut self, action: Action) -> Self
168	where
169		Action: axum::handler::Handler<ActionType, state::State<US>>,
170		ActionType: 'static,
171		US: 'static,
172		US: Clone,
173		US: Send + Sync,
174	{
175		if let Some(current_action) = self.action.take() {
176			self.action.replace(current_action.put(action));
177		} else {
178			self.action.replace(axum::routing::put(action));
179		}
180		self.methods.insert(axum::http::Method::PUT);
181		self
182	}
183
184	pub fn trace<Action, ActionType>(mut self, action: Action) -> Self
185	where
186		Action: axum::handler::Handler<ActionType, state::State<US>>,
187		ActionType: 'static,
188		US: 'static,
189		US: Clone,
190		US: Send + Sync,
191	{
192		if let Some(current_action) = self.action.take() {
193			self.action.replace(current_action.trace(action));
194		} else {
195			self.action.replace(axum::routing::trace(action));
196		}
197		self.methods.insert(axum::http::Method::TRACE);
198		self
199	}
200}
201
202impl<US> Router<US> {
203	pub fn layer<Layer>(mut self, layer: Layer) -> Self
204	where
205		US: 'static,
206		US: Clone,
207		US: Send + Sync,
208		Layer: Clone + Send + Sync + 'static,
209		Layer: tower_layer::Layer<axum::routing::Route>,
210		Layer::Service: tower_service::Service<
211			hyper::Request<hyper::Body>,
212			Error = std::convert::Infallible,
213		>,
214		Layer::Service: Clone + Send + 'static,
215		<Layer::Service as tower_service::Service<
216			hyper::Request<hyper::Body>,
217		>>::Response: axum::response::IntoResponse + 'static,
218		<Layer::Service as tower_service::Service<
219			hyper::Request<hyper::Body>,
220		>>::Future: Send + 'static,
221	{
222		if let Some(current_action) = self.action.take() {
223			self.action.replace(current_action.layer(layer));
224		}
225		self
226	}
227
228	pub fn route_layer<Layer>(mut self, layer: Layer) -> Self
229	where
230		US: 'static,
231		US: Clone,
232		US: Send + Sync,
233		Layer: Clone + Send + Sync + 'static,
234		Layer: tower_layer::Layer<axum::routing::Route>,
235		Layer::Service: tower_service::Service<
236			hyper::Request<hyper::Body>,
237			Error = std::convert::Infallible,
238		>,
239		Layer::Service: Clone + Send + 'static,
240		<Layer::Service as tower_service::Service<
241			hyper::Request<hyper::Body>,
242		>>::Response: axum::response::IntoResponse + 'static,
243		<Layer::Service as tower_service::Service<
244			hyper::Request<hyper::Body>,
245		>>::Future: Send + 'static,
246	{
247		if let Some(current_action) = self.action.take() {
248			self.action.replace(current_action.route_layer(layer));
249		}
250		self
251	}
252}
253
254// -------------- //
255// Implémentation // -> Interface
256// -------------- //
257
258macro_rules! router_impl {
259	(
260	impl RouterInterface for
261		$(
262			| ( $($generic:ident),* )
263		)* {}
264	) => {
265	$(
266		impl<State, $($generic),*> super::interface::RouterExt for ($($generic),*)
267		where
268			State: crate::state::StateInterface,
269			$(
270				$generic: super::interface::RouterExt<State = State>,
271			)*
272		{
273			type State = State;
274
275			fn routes() -> RouteCollection<Self::State> {
276				let mut router_collection = Self::router_collection();
277
278				$( router_collection.extend($generic::routes()); )*
279
280				router_collection
281			}
282		}
283	)*
284	};
285}
286
287router_impl! {
288	impl RouterInterface for
289		| (A, B)
290		| (A, B, C)
291		| (A, B, C, D)
292		| (A, B, C, D, E)
293		| (A, B, C, D, E, F)
294		| (A, B, C, D, E, F, G)
295		| (A, B, C, D, E, F, G, H)
296		| (A, B, C, D, E, F, G, H, I)
297		| (A, B, C, D, E, F, G, H, I, J)
298		| (A, B, C, D, E, F, G, H, I, J, K)
299		| (A, B, C, D, E, F, G, H, I, J, K, L)
300		| (A, B, C, D, E, F, G, H, I, J, K, L, M)
301		| (A, B, C, D, E, F, G, H, I, J, K, L, M, N)
302		| (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O)
303		| (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P)
304		| (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q)
305		| (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R)
306		| (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S)
307		| (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T)
308		| (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U)
309		| (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V)
310		| (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W)
311		| (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X)
312		| (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y)
313		| (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z)
314	{}
315}