Skip to main content

rustbasic_core/
router.rs

1use std::sync::Arc;
2use crate::requests::Request;
3
4
5pub type Response = http::Response<Vec<u8>>;
6
7pub trait IntoResponse {
8    fn into_response(self) -> Response;
9}
10
11impl IntoResponse for Response {
12    fn into_response(self) -> Response {
13        self
14    }
15}
16
17impl IntoResponse for &'static str {
18    fn into_response(self) -> Response {
19        http::Response::builder()
20            .header(http::header::CONTENT_TYPE, "text/plain; charset=utf-8")
21            .body(self.as_bytes().to_vec())
22            .unwrap()
23    }
24}
25
26impl IntoResponse for String {
27    fn into_response(self) -> Response {
28        http::Response::builder()
29            .header(http::header::CONTENT_TYPE, "text/plain; charset=utf-8")
30            .body(self.into_bytes())
31            .unwrap()
32    }
33}
34
35pub struct Html<T>(pub T);
36impl<T: Into<String>> IntoResponse for Html<T> {
37    fn into_response(self) -> Response {
38        http::Response::builder()
39            .header(http::header::CONTENT_TYPE, "text/html; charset=utf-8")
40            .body(self.0.into().into_bytes())
41            .unwrap()
42    }
43}
44
45pub struct Json<T>(pub T);
46impl<T: serde::Serialize> IntoResponse for Json<T> {
47    fn into_response(self) -> Response {
48        let body = serde_json::to_vec(&self.0).unwrap_or_default();
49        http::Response::builder()
50            .header(http::header::CONTENT_TYPE, "application/json")
51            .body(body)
52            .unwrap()
53    }
54}
55
56pub struct Redirect {
57    url: String,
58}
59impl Redirect {
60    pub fn to(url: &str) -> Self {
61        Self { url: url.to_string() }
62    }
63}
64impl IntoResponse for Redirect {
65    fn into_response(self) -> Response {
66        http::Response::builder()
67            .status(http::StatusCode::SEE_OTHER)
68            .header(http::header::LOCATION, &self.url)
69            .body(Vec::new())
70            .unwrap()
71    }
72}
73
74impl IntoResponse for serde_json::Value {
75    fn into_response(self) -> Response {
76        Json(self).into_response()
77    }
78}
79
80impl IntoResponse for http::StatusCode {
81    fn into_response(self) -> Response {
82        http::Response::builder()
83            .status(self)
84            .body(Vec::new())
85            .unwrap()
86    }
87}
88
89impl<T: IntoResponse, E: IntoResponse> IntoResponse for Result<T, E> {
90    fn into_response(self) -> Response {
91        match self {
92            Ok(r) => r.into_response(),
93            Err(e) => e.into_response(),
94        }
95    }
96}
97
98impl<T: IntoResponse> IntoResponse for (http::StatusCode, T) {
99    fn into_response(self) -> Response {
100        let mut res = self.1.into_response();
101        *res.status_mut() = self.0;
102        res
103    }
104}
105
106#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
107pub struct State<T>(pub T);
108
109#[crate::async_trait]
110pub trait Handler<T>: Send + Sync + 'static {
111    async fn call(&self, req: Request) -> Response;
112}
113
114#[crate::async_trait]
115pub trait ErasedHandler: Send + Sync + 'static {
116    async fn call(&self, req: Request) -> Response;
117}
118
119pub struct HandlerWrapper<H, T> {
120    pub(crate) handler: H,
121    pub(crate) _marker: std::marker::PhantomData<T>,
122}
123
124#[crate::async_trait]
125impl<H, T> ErasedHandler for HandlerWrapper<H, T>
126where
127    H: Handler<T>,
128    T: Send + Sync + 'static,
129{
130    async fn call(&self, req: Request) -> Response {
131        self.handler.call(req).await
132    }
133}
134
135// Arity 0: fn() -> R
136#[crate::async_trait]
137impl<F, Fut, R> Handler<()> for F
138where
139    F: Fn() -> Fut + Send + Sync + 'static,
140    Fut: std::future::Future<Output = R> + Send + 'static,
141    R: IntoResponse + Send + 'static,
142{
143    async fn call(&self, _req: Request) -> Response {
144        self().await.into_response()
145    }
146}
147
148// Arity 1: fn(Request) -> R
149#[crate::async_trait]
150impl<F, Fut, R> Handler<(Request,)> for F
151where
152    F: Fn(Request) -> Fut + Send + Sync + 'static,
153    Fut: std::future::Future<Output = R> + Send + 'static,
154    R: IntoResponse + Send + 'static,
155{
156    async fn call(&self, req: Request) -> Response {
157        self(req).await.into_response()
158    }
159}
160
161// Arity 2: fn(State<AppState>, Request) -> R
162#[crate::async_trait]
163impl<F, Fut, R> Handler<(State<crate::AppState>, Request)> for F
164where
165    F: Fn(State<crate::AppState>, Request) -> Fut + Send + Sync + 'static,
166    Fut: std::future::Future<Output = R> + Send + 'static,
167    R: IntoResponse + Send + 'static,
168{
169    async fn call(&self, req: Request) -> Response {
170        let state = State(req.state.clone());
171        self(state, req).await.into_response()
172    }
173}
174
175#[derive(Clone)]
176pub struct MethodRouter {
177    pub(crate) handlers: Vec<(http::Method, Arc<dyn ErasedHandler>)>,
178}
179
180pub fn get<H, T>(handler: H) -> MethodRouter
181where
182    H: Handler<T>,
183    T: Send + Sync + 'static,
184{
185    let wrapped: Arc<dyn ErasedHandler> = Arc::new(HandlerWrapper {
186        handler,
187        _marker: std::marker::PhantomData,
188    });
189    MethodRouter {
190        handlers: vec![(http::Method::GET, wrapped)],
191    }
192}
193
194pub fn post<H, T>(handler: H) -> MethodRouter
195where
196    H: Handler<T>,
197    T: Send + Sync + 'static,
198{
199    let wrapped: Arc<dyn ErasedHandler> = Arc::new(HandlerWrapper {
200        handler,
201        _marker: std::marker::PhantomData,
202    });
203    MethodRouter {
204        handlers: vec![(http::Method::POST, wrapped)],
205    }
206}
207
208pub fn put<H, T>(handler: H) -> MethodRouter
209where
210    H: Handler<T>,
211    T: Send + Sync + 'static,
212{
213    let wrapped: Arc<dyn ErasedHandler> = Arc::new(HandlerWrapper {
214        handler,
215        _marker: std::marker::PhantomData,
216    });
217    MethodRouter {
218        handlers: vec![(http::Method::PUT, wrapped)],
219    }
220}
221
222pub fn patch<H, T>(handler: H) -> MethodRouter
223where
224    H: Handler<T>,
225    T: Send + Sync + 'static,
226{
227    let wrapped: Arc<dyn ErasedHandler> = Arc::new(HandlerWrapper {
228        handler,
229        _marker: std::marker::PhantomData,
230    });
231    MethodRouter {
232        handlers: vec![(http::Method::PATCH, wrapped)],
233    }
234}
235
236pub fn delete<H, T>(handler: H) -> MethodRouter
237where
238    H: Handler<T>,
239    T: Send + Sync + 'static,
240{
241    let wrapped: Arc<dyn ErasedHandler> = Arc::new(HandlerWrapper {
242        handler,
243        _marker: std::marker::PhantomData,
244    });
245    MethodRouter {
246        handlers: vec![(http::Method::DELETE, wrapped)],
247    }
248}
249
250impl MethodRouter {
251    pub fn get<H, T>(mut self, handler: H) -> Self
252    where
253        H: Handler<T>,
254        T: Send + Sync + 'static,
255    {
256        let wrapped: Arc<dyn ErasedHandler> = Arc::new(HandlerWrapper {
257            handler,
258            _marker: std::marker::PhantomData,
259        });
260        self.handlers.push((http::Method::GET, wrapped));
261        self
262    }
263    
264    pub fn post<H, T>(mut self, handler: H) -> Self
265    where
266        H: Handler<T>,
267        T: Send + Sync + 'static,
268    {
269        let wrapped: Arc<dyn ErasedHandler> = Arc::new(HandlerWrapper {
270            handler,
271            _marker: std::marker::PhantomData,
272        });
273        self.handlers.push((http::Method::POST, wrapped));
274        self
275    }
276    
277    pub fn put<H, T>(mut self, handler: H) -> Self
278    where
279        H: Handler<T>,
280        T: Send + Sync + 'static,
281    {
282        let wrapped: Arc<dyn ErasedHandler> = Arc::new(HandlerWrapper {
283            handler,
284            _marker: std::marker::PhantomData,
285        });
286        self.handlers.push((http::Method::PUT, wrapped));
287        self
288    }
289
290    pub fn patch<H, T>(mut self, handler: H) -> Self
291    where
292        H: Handler<T>,
293        T: Send + Sync + 'static,
294    {
295        let wrapped: Arc<dyn ErasedHandler> = Arc::new(HandlerWrapper {
296            handler,
297            _marker: std::marker::PhantomData,
298        });
299        self.handlers.push((http::Method::PATCH, wrapped));
300        self
301    }
302
303    pub fn delete<H, T>(mut self, handler: H) -> Self
304    where
305        H: Handler<T>,
306        T: Send + Sync + 'static,
307    {
308        let wrapped: Arc<dyn ErasedHandler> = Arc::new(HandlerWrapper {
309            handler,
310            _marker: std::marker::PhantomData,
311        });
312        self.handlers.push((http::Method::DELETE, wrapped));
313        self
314    }
315}
316
317#[derive(Clone)]
318pub struct Router<S = ()> {
319    pub(crate) routes: Vec<Arc<Route>>,
320    pub(crate) middlewares: Vec<crate::middleware::MiddlewareFn>,
321    pub(crate) _marker: std::marker::PhantomData<fn() -> S>,
322}
323
324pub struct Route {
325    pub path: String,
326    pub handlers: Vec<(http::Method, Arc<dyn ErasedHandler>)>,
327    pub name: Option<String>,
328}
329
330pub static NAMED_ROUTES: std::sync::OnceLock<std::collections::HashMap<String, String>> = std::sync::OnceLock::new();
331
332pub fn get_named_routes() -> std::collections::HashMap<String, String> {
333    NAMED_ROUTES.get().cloned().unwrap_or_default()
334}
335
336
337struct MiddlewareHandler {
338    mw: crate::middleware::MiddlewareFn,
339    next: Arc<dyn ErasedHandler>,
340}
341
342#[crate::async_trait]
343impl ErasedHandler for MiddlewareHandler {
344    async fn call(&self, req: Request) -> Response {
345        let chain = Arc::new(crate::middleware::MiddlewareChain::End(self.next.clone()));
346        let next = crate::middleware::Next { chain };
347        (self.mw)(req, next).await
348    }
349}
350
351impl<S> Router<S> {
352    pub fn new() -> Self {
353        Self {
354            routes: Vec::new(),
355            middlewares: Vec::new(),
356            _marker: std::marker::PhantomData,
357        }
358    }
359
360    pub fn route(mut self, path: &str, method_router: MethodRouter) -> Self {
361        self.routes.push(Arc::new(Route {
362            path: path.to_string(),
363            handlers: method_router.handlers,
364            name: None,
365        }));
366        self
367    }
368
369    pub fn name(mut self, name: &str) -> Self {
370        if let Some(route) = self.routes.last_mut() {
371            let new_route = Route {
372                path: route.path.clone(),
373                handlers: route.handlers.clone(),
374                name: Some(name.to_string()),
375            };
376            *route = Arc::new(new_route);
377        }
378        self
379    }
380
381    pub fn get_json<T>(self, path: &str, data: T) -> Self
382    where
383        T: serde::Serialize + Clone + Send + Sync + 'static,
384    {
385        let data_clone = data.clone();
386        self.route(path, get(move || {
387            let data = data_clone.clone();
388            async move {
389                Json(data)
390            }
391        }))
392    }
393
394    pub fn get_redirect(self, path: &str, to_url: &str) -> Self {
395        let to_url = to_url.to_string();
396        self.route(path, get(move || {
397            let to = to_url.clone();
398            async move {
399                Redirect::to(&to)
400            }
401        }))
402    }
403
404    pub fn get_view(self, path: &str, template: &'static str, context: serde_json::Value) -> Self {
405        let context_clone = context.clone();
406        self.route(path, get(move |req: Request| {
407            let ctx = context_clone.clone();
408            async move {
409                crate::view::view(&req, template, ctx)
410            }
411        }))
412    }
413
414    pub fn merge(mut self, other: Router<S>) -> Self {
415        for other_route in other.routes {
416            let mut handlers_with_mw = Vec::new();
417            for (method, handler) in &other_route.handlers {
418                let mut current_handler = handler.clone();
419                for mw in other.middlewares.iter().rev() {
420                    let next_handler = current_handler.clone();
421                    let mw_clone = mw.clone();
422                    current_handler = Arc::new(MiddlewareHandler {
423                        mw: mw_clone,
424                        next: next_handler,
425                    });
426                }
427                handlers_with_mw.push((method.clone(), current_handler));
428            }
429            self.routes.push(Arc::new(Route {
430                path: other_route.path.clone(),
431                handlers: handlers_with_mw,
432                name: other_route.name.clone(),
433            }));
434        }
435        self
436    }
437
438    pub fn nest(mut self, prefix: &str, other: Router<S>) -> Self {
439        let clean_prefix = prefix.trim_end_matches('/');
440        for other_route in other.routes {
441            let mut handlers_with_mw = Vec::new();
442            for (method, handler) in &other_route.handlers {
443                let mut current_handler = handler.clone();
444                for mw in other.middlewares.iter().rev() {
445                    let next_handler = current_handler.clone();
446                    let mw_clone = mw.clone();
447                    current_handler = Arc::new(MiddlewareHandler {
448                        mw: mw_clone,
449                        next: next_handler,
450                    });
451                }
452                handlers_with_mw.push((method.clone(), current_handler));
453            }
454            let nested_path = format!("{}{}", clean_prefix, other_route.path);
455            self.routes.push(Arc::new(Route {
456                path: nested_path,
457                handlers: handlers_with_mw,
458                name: other_route.name.clone(),
459            }));
460        }
461        self
462    }
463
464    pub fn prefix(mut self, prefix: &str) -> Self {
465        let clean_prefix = prefix.trim_end_matches('/');
466        let clean_prefix = if clean_prefix.starts_with('/') {
467            clean_prefix.to_string()
468        } else {
469            format!("/{}", clean_prefix)
470        };
471        for route in &mut self.routes {
472            let mut path = route.path.clone();
473            if !path.starts_with('/') {
474                path = format!("/{}", path);
475            }
476            let new_path = format!("{}{}", clean_prefix, path);
477            *route = Arc::new(Route {
478                path: new_path,
479                handlers: route.handlers.clone(),
480                name: route.name.clone(),
481            });
482        }
483        self
484    }
485
486    pub fn layer(mut self, mw: crate::middleware::MiddlewareFn) -> Self {
487        self.middlewares.push(mw);
488        self
489    }
490}