1use crate::error::{Error, Result};
2use crate::types::{OxiditeRequest, OxiditeResponse};
3use crate::extract::FromRequest;
4use hyper::Method;
5use std::collections::HashMap;
6use std::future::Future;
7use std::pin::Pin;
8use std::sync::Arc;
9use std::task::{Context, Poll};
10use tower_service::Service;
11
12use regex::Regex;
13
14pub trait Endpoint: Send + Sync + 'static {
16 fn call(&self, req: OxiditeRequest) -> Pin<Box<dyn Future<Output = Result<OxiditeResponse>> + Send>>;
17}
18
19impl Endpoint for Arc<dyn Endpoint> {
20 fn call(&self, req: OxiditeRequest) -> Pin<Box<dyn Future<Output = Result<OxiditeResponse>> + Send>> {
21 (**self).call(req)
22 }
23}
24
25pub struct EndpointService(pub Arc<dyn Endpoint>);
26
27impl Clone for EndpointService {
28 fn clone(&self) -> Self {
29 Self(self.0.clone())
30 }
31}
32
33impl Service<OxiditeRequest> for EndpointService {
34 type Response = OxiditeResponse;
35 type Error = Error;
36 type Future = Pin<Box<dyn Future<Output = Result<OxiditeResponse>> + Send>>;
37
38 fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<std::result::Result<(), Self::Error>> {
39 Poll::Ready(Ok(()))
40 }
41
42 fn call(&mut self, req: OxiditeRequest) -> Self::Future {
43 self.0.call(req)
44 }
45}
46
47impl Endpoint for EndpointService {
48 fn call(&self, req: OxiditeRequest) -> Pin<Box<dyn Future<Output = Result<OxiditeResponse>> + Send>> {
49 self.0.call(req)
50 }
51}
52
53impl<S, E> Endpoint for tower_http::cors::Cors<S>
54where
55 S: Service<OxiditeRequest, Response = OxiditeResponse, Error = E> + Clone + Send + Sync + 'static,
56 S::Future: Send + 'static,
57 E: std::fmt::Display + Send + 'static,
58{
59 fn call(&self, req: OxiditeRequest) -> Pin<Box<dyn Future<Output = Result<OxiditeResponse>> + Send>> {
60
61 let this = self.clone();
62 Box::pin(async move {
63 let res = this.call(req).await.map_err(|e| Error::InternalServerError(e.to_string()))?;
64 Ok(res)
65 })
66 }
67}
68
69impl<S, E> Endpoint for tower_http::compression::Compression<S>
70where
71 S: Service<OxiditeRequest, Response = OxiditeResponse, Error = E> + Clone + Send + Sync + 'static,
72 S::Future: Send + 'static,
73 E: std::fmt::Display + Send + 'static,
74{
75 fn call(&self, req: OxiditeRequest) -> Pin<Box<dyn Future<Output = Result<OxiditeResponse>> + Send>> {
76
77 let this = self.clone();
78 Box::pin(async move {
79 let res = this.call(req).await.map_err(|e| Error::InternalServerError(e.to_string()))?;
80 Ok(res)
81 })
82 }
83}
84
85
86pub trait Handler<Args>: Clone + Send + Sync + 'static {
88 fn call(&self, req: OxiditeRequest) -> Pin<Box<dyn Future<Output = Result<OxiditeResponse>> + Send>>;
89}
90
91struct HandlerService<H, Args> {
93 handler: H,
94 _marker: std::marker::PhantomData<Args>,
95}
96
97impl<H, Args> Endpoint for HandlerService<H, Args>
98where
99 H: Handler<Args>,
100 Args: Send + Sync + 'static,
101{
102 fn call(&self, req: OxiditeRequest) -> Pin<Box<dyn Future<Output = Result<OxiditeResponse>> + Send>> {
103 self.handler.call(req)
104 }
105}
106
107impl<F, Fut> Handler<OxiditeRequest> for F
109where
110 F: Fn(OxiditeRequest) -> Fut + Clone + Send + Sync + 'static,
111 Fut: Future<Output = Result<OxiditeResponse>> + Send + 'static,
112{
113 fn call(&self, req: OxiditeRequest) -> Pin<Box<dyn Future<Output = Result<OxiditeResponse>> + Send>> {
114 let fut = self(req);
115 Box::pin(async move { fut.await })
116 }
117}
118
119impl<F, Fut> Handler<()> for F
121where
122 F: Fn() -> Fut + Clone + Send + Sync + 'static,
123 Fut: Future<Output = Result<OxiditeResponse>> + Send + 'static,
124{
125 fn call(&self, _req: OxiditeRequest) -> Pin<Box<dyn Future<Output = Result<OxiditeResponse>> + Send>> {
126 let fut = self();
127 Box::pin(async move { fut.await })
128 }
129}
130
131impl<F, Fut, T1> Handler<(T1,)> for F
133where
134 F: Fn(T1) -> Fut + Clone + Send + Sync + 'static,
135 Fut: Future<Output = Result<OxiditeResponse>> + Send + 'static,
136 T1: FromRequest + Send + 'static,
137{
138 fn call(&self, mut req: OxiditeRequest) -> Pin<Box<dyn Future<Output = Result<OxiditeResponse>> + Send>> {
139 let handler = self.clone();
140 Box::pin(async move {
141 let t1 = T1::from_request(&mut req).await?;
142 handler(t1).await
143 })
144 }
145}
146
147impl<F, Fut, T1, T2, T3, T4, T5, T6, T7, T8, T9> Handler<(T1, T2, T3, T4, T5, T6, T7, T8, T9)> for F
149where
150 F: Fn(T1, T2, T3, T4, T5, T6, T7, T8, T9) -> Fut + Clone + Send + Sync + 'static,
151 Fut: Future<Output = Result<OxiditeResponse>> + Send + 'static,
152 T1: FromRequest + Send + 'static,
153 T2: FromRequest + Send + 'static,
154 T3: FromRequest + Send + 'static,
155 T4: FromRequest + Send + 'static,
156 T5: FromRequest + Send + 'static,
157 T6: FromRequest + Send + 'static,
158 T7: FromRequest + Send + 'static,
159 T8: FromRequest + Send + 'static,
160 T9: FromRequest + Send + 'static,
161{
162 fn call(&self, mut req: OxiditeRequest) -> Pin<Box<dyn Future<Output = Result<OxiditeResponse>> + Send>> {
163 let handler = self.clone();
164 Box::pin(async move {
165 let t1 = T1::from_request(&mut req).await?;
166 let t2 = T2::from_request(&mut req).await?;
167 let t3 = T3::from_request(&mut req).await?;
168 let t4 = T4::from_request(&mut req).await?;
169 let t5 = T5::from_request(&mut req).await?;
170 let t6 = T6::from_request(&mut req).await?;
171 let t7 = T7::from_request(&mut req).await?;
172 let t8 = T8::from_request(&mut req).await?;
173 let t9 = T9::from_request(&mut req).await?;
174 handler(t1, t2, t3, t4, t5, t6, t7, t8, t9).await
175 })
176 }
177}
178
179impl<F, Fut, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> Handler<(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10)> for F
181where
182 F: Fn(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10) -> Fut + Clone + Send + Sync + 'static,
183 Fut: Future<Output = Result<OxiditeResponse>> + Send + 'static,
184 T1: FromRequest + Send + 'static,
185 T2: FromRequest + Send + 'static,
186 T3: FromRequest + Send + 'static,
187 T4: FromRequest + Send + 'static,
188 T5: FromRequest + Send + 'static,
189 T6: FromRequest + Send + 'static,
190 T7: FromRequest + Send + 'static,
191 T8: FromRequest + Send + 'static,
192 T9: FromRequest + Send + 'static,
193 T10: FromRequest + Send + 'static,
194{
195 fn call(&self, mut req: OxiditeRequest) -> Pin<Box<dyn Future<Output = Result<OxiditeResponse>> + Send>> {
196 let handler = self.clone();
197 Box::pin(async move {
198 let t1 = T1::from_request(&mut req).await?;
199 let t2 = T2::from_request(&mut req).await?;
200 let t3 = T3::from_request(&mut req).await?;
201 let t4 = T4::from_request(&mut req).await?;
202 let t5 = T5::from_request(&mut req).await?;
203 let t6 = T6::from_request(&mut req).await?;
204 let t7 = T7::from_request(&mut req).await?;
205 let t8 = T8::from_request(&mut req).await?;
206 let t9 = T9::from_request(&mut req).await?;
207 let t10 = T10::from_request(&mut req).await?;
208 handler(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10).await
209 })
210 }
211}
212
213impl<F, Fut, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11> Handler<(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11)> for F
215where
216 F: Fn(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11) -> Fut + Clone + Send + Sync + 'static,
217 Fut: Future<Output = Result<OxiditeResponse>> + Send + 'static,
218 T1: FromRequest + Send + 'static,
219 T2: FromRequest + Send + 'static,
220 T3: FromRequest + Send + 'static,
221 T4: FromRequest + Send + 'static,
222 T5: FromRequest + Send + 'static,
223 T6: FromRequest + Send + 'static,
224 T7: FromRequest + Send + 'static,
225 T8: FromRequest + Send + 'static,
226 T9: FromRequest + Send + 'static,
227 T10: FromRequest + Send + 'static,
228 T11: FromRequest + Send + 'static,
229{
230 fn call(&self, mut req: OxiditeRequest) -> Pin<Box<dyn Future<Output = Result<OxiditeResponse>> + Send>> {
231 let handler = self.clone();
232 Box::pin(async move {
233 let t1 = T1::from_request(&mut req).await?;
234 let t2 = T2::from_request(&mut req).await?;
235 let t3 = T3::from_request(&mut req).await?;
236 let t4 = T4::from_request(&mut req).await?;
237 let t5 = T5::from_request(&mut req).await?;
238 let t6 = T6::from_request(&mut req).await?;
239 let t7 = T7::from_request(&mut req).await?;
240 let t8 = T8::from_request(&mut req).await?;
241 let t9 = T9::from_request(&mut req).await?;
242 let t10 = T10::from_request(&mut req).await?;
243 let t11 = T11::from_request(&mut req).await?;
244 handler(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11).await
245 })
246 }
247}
248
249impl<F, Fut, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12> Handler<(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12)> for F
251where
252 F: Fn(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12) -> Fut + Clone + Send + Sync + 'static,
253 Fut: Future<Output = Result<OxiditeResponse>> + Send + 'static,
254 T1: FromRequest + Send + 'static,
255 T2: FromRequest + Send + 'static,
256 T3: FromRequest + Send + 'static,
257 T4: FromRequest + Send + 'static,
258 T5: FromRequest + Send + 'static,
259 T6: FromRequest + Send + 'static,
260 T7: FromRequest + Send + 'static,
261 T8: FromRequest + Send + 'static,
262 T9: FromRequest + Send + 'static,
263 T10: FromRequest + Send + 'static,
264 T11: FromRequest + Send + 'static,
265 T12: FromRequest + Send + 'static,
266{
267 fn call(&self, mut req: OxiditeRequest) -> Pin<Box<dyn Future<Output = Result<OxiditeResponse>> + Send>> {
268 let handler = self.clone();
269 Box::pin(async move {
270 let t1 = T1::from_request(&mut req).await?;
271 let t2 = T2::from_request(&mut req).await?;
272 let t3 = T3::from_request(&mut req).await?;
273 let t4 = T4::from_request(&mut req).await?;
274 let t5 = T5::from_request(&mut req).await?;
275 let t6 = T6::from_request(&mut req).await?;
276 let t7 = T7::from_request(&mut req).await?;
277 let t8 = T8::from_request(&mut req).await?;
278 let t9 = T9::from_request(&mut req).await?;
279 let t10 = T10::from_request(&mut req).await?;
280 let t11 = T11::from_request(&mut req).await?;
281 let t12 = T12::from_request(&mut req).await?;
282 handler(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12).await
283 })
284 }
285}
286
287impl<F, Fut, T1, T2> Handler<(T1, T2)> for F
289where
290 F: Fn(T1, T2) -> Fut + Clone + Send + Sync + 'static,
291 Fut: Future<Output = Result<OxiditeResponse>> + Send + 'static,
292 T1: FromRequest + Send + 'static,
293 T2: FromRequest + Send + 'static,
294{
295 fn call(&self, mut req: OxiditeRequest) -> Pin<Box<dyn Future<Output = Result<OxiditeResponse>> + Send>> {
296 let handler = self.clone();
297 Box::pin(async move {
298 let t1 = T1::from_request(&mut req).await?;
299 let t2 = T2::from_request(&mut req).await?;
300 handler(t1, t2).await
301 })
302 }
303}
304
305impl<F, Fut, T1, T2, T3> Handler<(T1, T2, T3)> for F
307where
308 F: Fn(T1, T2, T3) -> Fut + Clone + Send + Sync + 'static,
309 Fut: Future<Output = Result<OxiditeResponse>> + Send + 'static,
310 T1: FromRequest + Send + 'static,
311 T2: FromRequest + Send + 'static,
312 T3: FromRequest + Send + 'static,
313{
314 fn call(&self, mut req: OxiditeRequest) -> Pin<Box<dyn Future<Output = Result<OxiditeResponse>> + Send>> {
315 let handler = self.clone();
316 Box::pin(async move {
317 let t1 = T1::from_request(&mut req).await?;
318 let t2 = T2::from_request(&mut req).await?;
319 let t3 = T3::from_request(&mut req).await?;
320 handler(t1, t2, t3).await
321 })
322 }
323}
324
325impl<F, Fut, T1, T2, T3, T4> Handler<(T1, T2, T3, T4)> for F
327where
328 F: Fn(T1, T2, T3, T4) -> Fut + Clone + Send + Sync + 'static,
329 Fut: Future<Output = Result<OxiditeResponse>> + Send + 'static,
330 T1: FromRequest + Send + 'static,
331 T2: FromRequest + Send + 'static,
332 T3: FromRequest + Send + 'static,
333 T4: FromRequest + Send + 'static,
334{
335 fn call(&self, mut req: OxiditeRequest) -> Pin<Box<dyn Future<Output = Result<OxiditeResponse>> + Send>> {
336 let handler = self.clone();
337 Box::pin(async move {
338 let t1 = T1::from_request(&mut req).await?;
339 let t2 = T2::from_request(&mut req).await?;
340 let t3 = T3::from_request(&mut req).await?;
341 let t4 = T4::from_request(&mut req).await?;
342 handler(t1, t2, t3, t4).await
343 })
344 }
345}
346
347impl<F, Fut, T1, T2, T3, T4, T5> Handler<(T1, T2, T3, T4, T5)> for F
349where
350 F: Fn(T1, T2, T3, T4, T5) -> Fut + Clone + Send + Sync + 'static,
351 Fut: Future<Output = Result<OxiditeResponse>> + Send + 'static,
352 T1: FromRequest + Send + 'static,
353 T2: FromRequest + Send + 'static,
354 T3: FromRequest + Send + 'static,
355 T4: FromRequest + Send + 'static,
356 T5: FromRequest + Send + 'static,
357{
358 fn call(&self, mut req: OxiditeRequest) -> Pin<Box<dyn Future<Output = Result<OxiditeResponse>> + Send>> {
359 let handler = self.clone();
360 Box::pin(async move {
361 let t1 = T1::from_request(&mut req).await?;
362 let t2 = T2::from_request(&mut req).await?;
363 let t3 = T3::from_request(&mut req).await?;
364 let t4 = T4::from_request(&mut req).await?;
365 let t5 = T5::from_request(&mut req).await?;
366 handler(t1, t2, t3, t4, t5).await
367 })
368 }
369}
370
371impl<F, Fut, T1, T2, T3, T4, T5, T6> Handler<(T1, T2, T3, T4, T5, T6)> for F
373where
374 F: Fn(T1, T2, T3, T4, T5, T6) -> Fut + Clone + Send + Sync + 'static,
375 Fut: Future<Output = Result<OxiditeResponse>> + Send + 'static,
376 T1: FromRequest + Send + 'static,
377 T2: FromRequest + Send + 'static,
378 T3: FromRequest + Send + 'static,
379 T4: FromRequest + Send + 'static,
380 T5: FromRequest + Send + 'static,
381 T6: FromRequest + Send + 'static,
382{
383 fn call(&self, mut req: OxiditeRequest) -> Pin<Box<dyn Future<Output = Result<OxiditeResponse>> + Send>> {
384 let handler = self.clone();
385 Box::pin(async move {
386 let t1 = T1::from_request(&mut req).await?;
387 let t2 = T2::from_request(&mut req).await?;
388 let t3 = T3::from_request(&mut req).await?;
389 let t4 = T4::from_request(&mut req).await?;
390 let t5 = T5::from_request(&mut req).await?;
391 let t6 = T6::from_request(&mut req).await?;
392 handler(t1, t2, t3, t4, t5, t6).await
393 })
394 }
395}
396
397impl<F, Fut, T1, T2, T3, T4, T5, T6, T7> Handler<(T1, T2, T3, T4, T5, T6, T7)> for F
399where
400 F: Fn(T1, T2, T3, T4, T5, T6, T7) -> Fut + Clone + Send + Sync + 'static,
401 Fut: Future<Output = Result<OxiditeResponse>> + Send + 'static,
402 T1: FromRequest + Send + 'static,
403 T2: FromRequest + Send + 'static,
404 T3: FromRequest + Send + 'static,
405 T4: FromRequest + Send + 'static,
406 T5: FromRequest + Send + 'static,
407 T6: FromRequest + Send + 'static,
408 T7: FromRequest + Send + 'static,
409{
410 fn call(&self, mut req: OxiditeRequest) -> Pin<Box<dyn Future<Output = Result<OxiditeResponse>> + Send>> {
411 let handler = self.clone();
412 Box::pin(async move {
413 let t1 = T1::from_request(&mut req).await?;
414 let t2 = T2::from_request(&mut req).await?;
415 let t3 = T3::from_request(&mut req).await?;
416 let t4 = T4::from_request(&mut req).await?;
417 let t5 = T5::from_request(&mut req).await?;
418 let t6 = T6::from_request(&mut req).await?;
419 let t7 = T7::from_request(&mut req).await?;
420 handler(t1, t2, t3, t4, t5, t6, t7).await
421 })
422 }
423}
424
425impl<F, Fut, T1, T2, T3, T4, T5, T6, T7, T8> Handler<(T1, T2, T3, T4, T5, T6, T7, T8)> for F
427where
428 F: Fn(T1, T2, T3, T4, T5, T6, T7, T8) -> Fut + Clone + Send + Sync + 'static,
429 Fut: Future<Output = Result<OxiditeResponse>> + Send + 'static,
430 T1: FromRequest + Send + 'static,
431 T2: FromRequest + Send + 'static,
432 T3: FromRequest + Send + 'static,
433 T4: FromRequest + Send + 'static,
434 T5: FromRequest + Send + 'static,
435 T6: FromRequest + Send + 'static,
436 T7: FromRequest + Send + 'static,
437 T8: FromRequest + Send + 'static,
438{
439 fn call(&self, mut req: OxiditeRequest) -> Pin<Box<dyn Future<Output = Result<OxiditeResponse>> + Send>> {
440 let handler = self.clone();
441 Box::pin(async move {
442 let t1 = T1::from_request(&mut req).await?;
443 let t2 = T2::from_request(&mut req).await?;
444 let t3 = T3::from_request(&mut req).await?;
445 let t4 = T4::from_request(&mut req).await?;
446 let t5 = T5::from_request(&mut req).await?;
447 let t6 = T6::from_request(&mut req).await?;
448 let t7 = T7::from_request(&mut req).await?;
449 let t8 = T8::from_request(&mut req).await?;
450 handler(t1, t2, t3, t4, t5, t6, t7, t8).await
451 })
452 }
453}
454
455struct Route {
456 pattern: Regex,
457 param_names: Vec<String>,
458 handler: Arc<dyn Endpoint>,
459}
460
461#[derive(Clone)]
462pub struct Router {
463 routes: HashMap<Method, Vec<Arc<Route>>>,
464 extensions: Arc<std::sync::RwLock<http::Extensions>>,
465 middleware: Vec<Arc<dyn Fn(Arc<dyn Endpoint>) -> Arc<dyn Endpoint> + Send + Sync>>,
466}
467
468impl Router {
469 pub fn new() -> Self {
470 Self {
471 routes: HashMap::new(),
472 extensions: Arc::new(std::sync::RwLock::new(http::Extensions::new())),
473 middleware: Vec::new(),
474 }
475 }
476
477 pub fn with_state<T: Clone + Send + Sync + 'static>(&mut self, state: T) {
479 if let Ok(mut exts) = self.extensions.write() {
480 exts.insert(state);
481 }
482 }
483
484 pub fn get<H, Args>(&mut self, path: &str, handler: H)
485 where
486 H: Handler<Args>,
487 Args: Send + Sync + 'static,
488 {
489 self.add_route(Method::GET, path, handler);
490 }
491
492 pub fn post<H, Args>(&mut self, path: &str, handler: H)
493 where
494 H: Handler<Args>,
495 Args: Send + Sync + 'static,
496 {
497 self.add_route(Method::POST, path, handler);
498 }
499
500 pub fn put<H, Args>(&mut self, path: &str, handler: H)
501 where
502 H: Handler<Args>,
503 Args: Send + Sync + 'static,
504 {
505 self.add_route(Method::PUT, path, handler);
506 }
507
508 pub fn delete<H, Args>(&mut self, path: &str, handler: H)
509 where
510 H: Handler<Args>,
511 Args: Send + Sync + 'static,
512 {
513 self.add_route(Method::DELETE, path, handler);
514 }
515
516 pub fn patch<H, Args>(&mut self, path: &str, handler: H)
517 where
518 H: Handler<Args>,
519 Args: Send + Sync + 'static,
520 {
521 self.add_route(Method::PATCH, path, handler);
522 }
523
524 pub fn layer<L>(mut self, layer: L) -> Self
528 where
529 L: tower::Layer<EndpointService> + Send + Sync + 'static,
530 L::Service: Endpoint,
531 {
532 let layer = Arc::new(layer);
533 self.middleware.push(Arc::new(move |endpoint| {
534 Arc::new(layer.layer(EndpointService(endpoint)))
535 }));
536 self
537 }
538
539 pub fn with_layer<L>(self, layer: L) -> Self
541 where
542 L: tower::Layer<EndpointService> + Send + Sync + 'static,
543 L::Service: Endpoint,
544 {
545 self.layer(layer)
546 }
547
548 fn add_route<H, Args>(&mut self, method: Method, path: &str, handler: H)
549 where
550 H: Handler<Args>,
551 Args: Send + Sync + 'static,
552 {
553 let (pattern, param_names) = compile_path(path);
554 let mut endpoint: Arc<dyn Endpoint> = Arc::new(HandlerService {
555 handler,
556 _marker: std::marker::PhantomData,
557 });
558
559 for mw in self.middleware.iter().rev() {
561 endpoint = mw(endpoint);
562 }
563
564 let route = Arc::new(Route {
565 pattern,
566 param_names,
567 handler: endpoint,
568 });
569
570 self.routes
571 .entry(method)
572 .or_insert_with(Vec::new)
573 .push(route);
574 }
575
576 pub async fn handle(&self, mut req: OxiditeRequest) -> Result<OxiditeResponse> {
577 req.extensions_mut().insert(self.extensions.clone());
578 let method = req.method().clone();
579 let path = req.uri().path().to_string();
580
581 let try_match = |target_method: &Method, req: &mut OxiditeRequest| -> Option<Arc<Route>> {
583 if let Some(routes) = self.routes.get(target_method) {
584 for route in routes {
585 if let Some(captures) = route.pattern.captures(&path) {
586 let mut params = serde_json::Map::new();
588 for (i, name) in route.param_names.iter().enumerate() {
589 if let Some(value) = captures.get(i + 1) {
590 params.insert(
591 name.clone(),
592 serde_json::Value::String(value.as_str().to_string()),
593 );
594 }
595 }
596
597 if !params.is_empty() {
599 req.extensions_mut().insert(crate::extract::PathParams(
600 serde_json::Value::Object(params),
601 ));
602 }
603
604 return Some(route.clone());
605 }
606 }
607 }
608 None
609 };
610
611 if let Some(route) = try_match(&method, &mut req) {
613 req.extensions_mut().insert(self.extensions.clone());
615 return route.handler.call(req).await;
616 }
617
618 if method == Method::HEAD {
620 if let Some(route) = try_match(&Method::GET, &mut req) {
621 req.extensions_mut().insert(self.extensions.clone());
623 return route.handler.call(req).await;
626 }
627 }
628
629 let allowed_methods: Vec<String> = self
631 .routes
632 .iter()
633 .filter(|(route_method, _)| **route_method != method)
634 .filter_map(|(route_method, routes)| {
635 if routes.iter().any(|route| route.pattern.is_match(&path)) {
636 Some(route_method.as_str().to_string())
637 } else {
638 None
639 }
640 })
641 .collect();
642 if !allowed_methods.is_empty() {
643 return Err(Error::MethodNotAllowed(format!(
644 "{} {} (allowed: {})",
645 method,
646 path,
647 allowed_methods.join(", ")
648 )));
649 }
650
651 Err(Error::NotFound("Route not found".to_string()))
652 }
653}
654
655impl Service<OxiditeRequest> for Router {
656 type Response = OxiditeResponse;
657 type Error = Error;
658 type Future = Pin<Box<dyn Future<Output = Result<Self::Response>> + Send>>;
659
660 fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<std::result::Result<(), Self::Error>> {
661 Poll::Ready(Ok(()))
662 }
663
664 fn call(&mut self, req: OxiditeRequest) -> Self::Future {
665 let router = self.clone();
666 Box::pin(async move {
667 router.handle(req).await
668 })
669 }
670}
671
672impl Default for Router {
673 fn default() -> Self {
674 Self::new()
675 }
676}
677
678fn compile_path(path: &str) -> (Regex, Vec<String>) {
681 let mut pattern = String::from("^");
682 let mut param_names = Vec::new();
683 let mut chars = path.chars().peekable();
684
685 while let Some(ch) = chars.next() {
686 match ch {
687 ':' => {
688 let mut param_name = String::new();
690 while let Some(&next_ch) = chars.peek() {
691 if next_ch.is_alphanumeric() || next_ch == '_' {
692 param_name.push(next_ch);
693 chars.next();
694 } else {
695 break;
696 }
697 }
698 param_names.push(param_name);
699 pattern.push_str("([^/]+)");
700 }
701 '*' => {
702 pattern.push_str("(.*)");
704 }
705 '.' | '+' | '?' | '^' | '$' | '(' | ')' | '[' | ']' | '{' | '}' | '|' | '\\' => {
706 pattern.push('\\');
708 pattern.push(ch);
709 }
710 _ => {
711 pattern.push(ch);
712 }
713 }
714 }
715
716 pattern.push('$');
717 let regex = Regex::new(&pattern).expect("Invalid route pattern");
718 (regex, param_names)
719}
720
721pub trait IntoHandler<Args>: Handler<Args> + Sized {
740 fn into_handler(self) -> Self {
741 self
742 }
743}
744
745impl<H, Args> IntoHandler<Args> for H where H: Handler<Args> {}
746
747pub fn handler_fn<H, Args>(handler: H) -> H
765where
766 H: IntoHandler<Args>,
767 Args: Send + Sync + 'static,
768{
769 handler
770}
771
772#[cfg(test)]
773mod tests {
774 use super::*;
775 use crate::types::BoxBody;
776
777 #[test]
778 fn test_compile_path() {
779 let (regex, params) = compile_path("/users/:id");
780 assert_eq!(params, vec!["id"]);
781 assert!(regex.is_match("/users/123"));
782 assert!(!regex.is_match("/users/123/posts"));
783
784 let (regex, params) = compile_path("/users/:user_id/posts/:post_id");
785 assert_eq!(params, vec!["user_id", "post_id"]);
786 assert!(regex.is_match("/users/1/posts/2"));
787 }
788
789 #[test]
790 fn test_exact_match() {
791 let (regex, params) = compile_path("/users");
792 assert_eq!(params.len(), 0);
793 assert!(regex.is_match("/users"));
794 assert!(!regex.is_match("/users/123"));
795 }
796
797 #[tokio::test]
798 async fn test_handler_with_12_extractors() {
799 use crate::extract::State;
800
801 #[derive(Clone)]
802 struct AppState;
803
804 async fn h12(
805 _s1: State<AppState>,
806 _s2: State<AppState>,
807 _s3: State<AppState>,
808 _s4: State<AppState>,
809 _s5: State<AppState>,
810 _s6: State<AppState>,
811 _s7: State<AppState>,
812 _s8: State<AppState>,
813 _s9: State<AppState>,
814 _s10: State<AppState>,
815 _s11: State<AppState>,
816 _s12: State<AppState>,
817 ) -> Result<OxiditeResponse> {
818 Ok(OxiditeResponse::text("ok"))
819 }
820
821 let mut router = Router::new();
822 router.with_state(AppState);
823 router.get("/", h12);
824
825 let req = http::Request::builder()
826 .method(Method::GET)
827 .uri("/")
828 .body(BoxBody::default())
829 .expect("request");
830
831 let result = router.handle(req).await.expect("handle");
832 assert_eq!(result.status(), http::StatusCode::OK);
833 }
834
835 #[tokio::test]
836 async fn test_method_not_allowed_when_path_exists() {
837 let mut router = Router::new();
838 router.get("/users", || async { Ok(crate::OxiditeResponse::text("ok")) });
839 let req = http::Request::builder()
840 .method(Method::POST)
841 .uri("/users")
842 .body(BoxBody::default())
843 .expect("request");
844
845 let result = router.handle(req).await;
846 assert!(matches!(result, Err(Error::MethodNotAllowed(_))));
847 }
848
849 #[tokio::test]
850 async fn test_not_found_when_path_missing() {
851 let router = Router::new();
852 let req = http::Request::builder()
853 .method(Method::GET)
854 .uri("/missing")
855 .body(BoxBody::default())
856 .expect("request");
857
858 let result = router.handle(req).await;
859 assert!(matches!(result, Err(Error::NotFound(_))));
860 }
861
862 #[tokio::test]
863 async fn test_handler_with_8_extractors() {
864 use crate::extract::State;
865
866 #[derive(Clone)]
867 struct AppState;
868
869 async fn h8(
870 _s1: State<AppState>,
871 _s2: State<AppState>,
872 _s3: State<AppState>,
873 _s4: State<AppState>,
874 _s5: State<AppState>,
875 _s6: State<AppState>,
876 _s7: State<AppState>,
877 _s8: State<AppState>,
878 ) -> Result<OxiditeResponse> {
879 Ok(OxiditeResponse::text("ok"))
880 }
881
882 let mut router = Router::new();
883 router.with_state(AppState);
884 router.get("/", h8);
885
886 let req = http::Request::builder()
887 .method(Method::GET)
888 .uri("/")
889 .body(BoxBody::default())
890 .expect("request");
891
892 let result = router.handle(req).await.expect("handle");
893 assert_eq!(result.status(), http::StatusCode::OK);
894 }
895
896 #[tokio::test]
897 async fn test_router_layer() {
898 use tower::Layer;
899
900 struct MyMiddleware<S>(S);
901 impl<S: Endpoint> Endpoint for MyMiddleware<S> {
902 fn call(&self, mut req: OxiditeRequest) -> Pin<Box<dyn Future<Output = Result<OxiditeResponse>> + Send>> {
903 req.extensions_mut().insert("middleware_called".to_string());
904 self.0.call(req)
905 }
906 }
907
908 struct MyLayer;
909 impl<S> Layer<S> for MyLayer {
910 type Service = MyMiddleware<S>;
911 fn layer(&self, inner: S) -> Self::Service {
912 MyMiddleware(inner)
913 }
914 }
915
916 let mut router = Router::new()
921 .layer(MyLayer);
922 router.get("/", |req: OxiditeRequest| async move {
923 if req.extensions().get::<String>().map(|s| s == "middleware_called").unwrap_or(false) {
924 Ok(OxiditeResponse::text("middleware_ok"))
925 } else {
926 Ok(OxiditeResponse::text("middleware_fail"))
927 }
928 });
929
930 let req = http::Request::builder()
931 .method(Method::GET)
932 .uri("/")
933 .body(BoxBody::default())
934 .expect("request");
935
936 let res = router.handle(req).await.expect("handle");
937 let hyper_res: hyper::Response<crate::types::BoxBody> = res.into();
938 let body = hyper_res.into_body();
939 use http_body_util::BodyExt;
940 let bytes = body.collect().await.unwrap().to_bytes();
941 assert_eq!(bytes, "middleware_ok");
942 }
943}