Skip to main content

oxidite_core/
router.rs

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
14/// Trait for type-erased handlers stored in the router
15pub 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
86/// Trait for async functions that can be used as handlers
87pub trait Handler<Args>: Clone + Send + Sync + 'static {
88    fn call(&self, req: OxiditeRequest) -> Pin<Box<dyn Future<Output = Result<OxiditeResponse>> + Send>>;
89}
90
91// Wrapper to convert Handler<Args> into Endpoint
92struct 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
107// Implement Handler for Fn(OxiditeRequest) -> Fut
108impl<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
119// Implement Handler for Fn() -> Fut
120impl<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
131// Implement Handler for Fn(T1) -> Fut
132impl<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
147// Implement Handler for Fn(T1, T2, ..., T9) -> Fut
148impl<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
179// Implement Handler for Fn(T1, T2, ..., T10) -> Fut
180impl<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
213// Implement Handler for Fn(T1, T2, ..., T11) -> Fut
214impl<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
249// Implement Handler for Fn(T1, T2, ..., T12) -> Fut
250impl<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
287// Implement Handler for Fn(T1, T2) -> Fut
288impl<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
305// Implement Handler for Fn(T1, T2, T3) -> Fut
306impl<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
325// Implement Handler for Fn(T1, T2, T3, T4) -> Fut
326impl<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
347// Implement Handler for Fn(T1, T2, T3, T4, T5) -> Fut
348impl<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
371// Implement Handler for Fn(T1, T2, T3, T4, T5, T6) -> Fut
372impl<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
397// Implement Handler for Fn(T1, T2, T3, T4, T5, T6, T7) -> Fut
398impl<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
425// Implement Handler for Fn(T1, T2, T3, T4, T5, T6, T7, T8) -> Fut
426impl<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    /// Add a shared state to the router that will be available in all handlers
478    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    /// Add a middleware layer to all routes in the router.
525    ///
526    /// The layer must implement `tower::Layer<EndpointService>` and return a new `Endpoint`.
527    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    /// Alias for `.layer()`.
540    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        // Apply router-level middleware in reverse order (so the first added is the outermost)
560        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        // Helper to try matching routes for a specific method
582        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                        // Extract path parameters
587                        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                        // Store params in request extensions
598                        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        // 1. Try exact method match
612        if let Some(route) = try_match(&method, &mut req) {
613            // Add router extensions to request so State extractor can find global state
614            req.extensions_mut().insert(self.extensions.clone());
615            return route.handler.call(req).await;
616        }
617
618        // 2. If HEAD, try GET
619        if method == Method::HEAD {
620            if let Some(route) = try_match(&Method::GET, &mut req) {
621                // Add router extensions to request so State extractor can find global state
622                req.extensions_mut().insert(self.extensions.clone());
623                // For HEAD requests, we execute the GET handler but the server/hyper 
624                // will strip the body automatically since it's a HEAD response.
625                return route.handler.call(req).await;
626            }
627        }
628
629        // 3. Path exists for other methods => method not allowed
630        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
678/// Compile a route path pattern into a regex
679/// Converts `/users/:id` to `^/users/([^/]+)$` and returns param names
680fn 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                // Extract parameter name
689                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                // Wildcard
703                pattern.push_str("(.*)");
704            }
705            '.' | '+' | '?' | '^' | '$' | '(' | ')' | '[' | ']' | '{' | '}' | '|' | '\\' => {
706                // Escape regex special characters
707                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
721/// Trait that provides compile-time verification that a function is a valid handler.
722///
723/// This is used by the [`handler_fn`] function to give clear, readable error messages
724/// when a function doesn't satisfy the handler requirements, rather than the cryptic
725/// trait-bound errors that would otherwise surface from the router.
726///
727/// # Example
728///
729/// ```rust,ignore
730/// use oxidite::prelude::*;
731///
732/// // This compiles because the function matches Handler<(State<Arc<AppState>>,)>
733/// let h = handler_fn(my_handler);
734/// router.get("/users", h);
735///
736/// // This would fail at compile time with a clear error if the function
737/// // has extractors that don't implement FromRequest.
738/// ```
739pub 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
747/// Compile-time handler verification helper.
748///
749/// Wraps a handler function and ensures at compile time that all its extractors
750/// implement `FromRequest`. Provides clearer error messages than raw trait bounds.
751///
752/// # Example
753///
754/// ```rust,ignore
755/// use oxidite::prelude::*;
756///
757/// async fn index(State(s): State<Arc<AppState>>) -> Result<OxiditeResponse> {
758///     Ok(response::json(serde_json::json!({"ok": true})))
759/// }
760///
761/// // Verified at compile time:
762/// router.get("/", handler_fn(index));
763/// ```
764pub 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        // We need to check if extensions were modified.
917        // But the handler in this test doesn't check it.
918        // Let's modify the handler to check.
919
920        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}