1#[cfg(test)]
53mod tests;
54
55use std::sync::Arc;
56
57use crate::application::Application;
58use crate::middleware::Middleware;
59use crate::request::Request;
60use crate::response::Response;
61use crate::router::PathParams;
62use crate::server::ConnectionInfo;
63
64pub type Guard<S> = Arc<dyn Fn(&Request, &ConnectionInfo, &S) -> Result<(), Response> + Send + Sync>;
67
68pub(crate) type SyncHandler<S> = Arc<dyn Fn(&Request, &PathParams, &ConnectionInfo, &Arc<S>) -> Response + Send + Sync>;
70
71pub(crate) struct GroupRoute<H> {
73 pub(crate) method: &'static str,
74 pub(crate) pattern: String,
75 pub(crate) name: Option<String>,
76 pub(crate) handler: H,
77}
78
79pub fn join_path(prefix: &str, pattern: &str) -> String {
82 let prefix = prefix.trim_end_matches('/');
83 let pattern = pattern.trim_start_matches('/');
84 let joined = match (prefix.is_empty(), pattern.is_empty()) {
85 (_, true) => prefix.to_string(),
86 (true, false) => format!("/{pattern}"),
87 (false, false) => format!("{prefix}/{pattern}"),
88 };
89 if joined.is_empty() {
90 "/".to_string()
91 } else if joined.starts_with('/') {
92 joined
93 } else {
94 format!("/{joined}")
95 }
96}
97
98fn resource_name(path: &str) -> String {
100 path.rsplit('/').find(|s| !s.is_empty() && !s.starts_with([':', '*', '{'])).unwrap_or("resource").to_string()
101}
102
103struct Endpoint<'a, S> {
105 handler: &'a SyncHandler<S>,
106 params: &'a PathParams,
107 state: &'a Arc<S>,
108}
109
110impl<S> Application for Endpoint<'_, S> {
111 fn execute(&self, request: &Request, connection: &ConnectionInfo) -> Result<Response, String> {
112 Ok((self.handler)(request, self.params, connection, self.state))
113 }
114}
115
116struct Rest<'a> {
118 layers: &'a [Arc<dyn Middleware>],
119 endpoint: &'a dyn Application,
120}
121
122impl Application for Rest<'_> {
123 fn execute(&self, request: &Request, connection: &ConnectionInfo) -> Result<Response, String> {
124 match self.layers.split_first() {
125 Some((layer, layers)) => layer.handle(request, connection, &Rest { layers, endpoint: self.endpoint }),
126 None => self.endpoint.execute(request, connection),
127 }
128 }
129}
130
131fn internal_error(message: String) -> Response {
132 use crate::error::{AppError, IntoResponse};
133 AppError::Internal(message).into_response()
134}
135
136fn wrap_sync<S: Send + Sync + 'static>(handler: SyncHandler<S>, guards: Arc<[Guard<S>]>, layers: Arc<[Arc<dyn Middleware>]>) -> SyncHandler<S> {
138 if guards.is_empty() && layers.is_empty() {
139 return handler;
140 }
141 Arc::new(move |request, params, connection, state| {
142 for guard in guards.iter() {
143 if let Err(response) = guard(request, connection, state) {
144 return response;
145 }
146 }
147 if layers.is_empty() {
148 return handler(request, params, connection, state);
149 }
150 let endpoint = Endpoint { handler: &handler, params, state };
151 match (Rest { layers: &layers, endpoint: &endpoint }).execute(request, connection) {
152 Ok(response) => response,
153 Err(message) => internal_error(message),
154 }
155 })
156}
157
158pub struct Group<S> {
163 prefix: String,
164 guards: Vec<Guard<S>>,
165 layers: Vec<Arc<dyn Middleware>>,
166 routes: Vec<GroupRoute<SyncHandler<S>>>,
167}
168
169impl<S: Send + Sync + 'static> Group<S> {
170 pub(crate) fn new(prefix: &str) -> Self {
171 Group { prefix: prefix.to_string(), guards: Vec::new(), layers: Vec::new(), routes: Vec::new() }
172 }
173
174 fn push(mut self, method: &'static str, pattern: &str, handler: SyncHandler<S>) -> Self {
175 self.routes.push(GroupRoute { method, pattern: join_path(&self.prefix, pattern), name: None, handler });
176 self
177 }
178
179 pub fn guard<G>(mut self, guard: G) -> Self
181 where
182 G: Fn(&Request, &ConnectionInfo, &S) -> Result<(), Response> + Send + Sync + 'static,
183 {
184 self.guards.push(Arc::new(guard));
185 self
186 }
187
188 pub fn wrap<M: Middleware + 'static>(mut self, layer: M) -> Self {
191 self.layers.push(Arc::new(layer));
192 self
193 }
194
195 pub fn name(mut self, name: &str) -> Self {
197 if let Some(route) = self.routes.last_mut() {
198 route.name = Some(name.to_string());
199 }
200 self
201 }
202
203 pub fn get<F>(self, pattern: &str, handler: F) -> Self
205 where
206 F: Fn(&Request, &PathParams, &ConnectionInfo, &S) -> Response + Send + Sync + 'static,
207 {
208 self.push("GET", pattern, Arc::new(move |r, p, c, s| handler(r, p, c, s)))
209 }
210
211 pub fn post<F>(self, pattern: &str, handler: F) -> Self
213 where
214 F: Fn(&Request, &PathParams, &ConnectionInfo, &S) -> Response + Send + Sync + 'static,
215 {
216 self.push("POST", pattern, Arc::new(move |r, p, c, s| handler(r, p, c, s)))
217 }
218
219 pub fn put<F>(self, pattern: &str, handler: F) -> Self
221 where
222 F: Fn(&Request, &PathParams, &ConnectionInfo, &S) -> Response + Send + Sync + 'static,
223 {
224 self.push("PUT", pattern, Arc::new(move |r, p, c, s| handler(r, p, c, s)))
225 }
226
227 pub fn patch<F>(self, pattern: &str, handler: F) -> Self
229 where
230 F: Fn(&Request, &PathParams, &ConnectionInfo, &S) -> Response + Send + Sync + 'static,
231 {
232 self.push("PATCH", pattern, Arc::new(move |r, p, c, s| handler(r, p, c, s)))
233 }
234
235 pub fn delete<F>(self, pattern: &str, handler: F) -> Self
237 where
238 F: Fn(&Request, &PathParams, &ConnectionInfo, &S) -> Response + Send + Sync + 'static,
239 {
240 self.push("DELETE", pattern, Arc::new(move |r, p, c, s| handler(r, p, c, s)))
241 }
242
243 pub fn route<H: crate::handler::Handler<S>>(self, handler: H) -> Self {
246 self.push(H::METHOD, H::PATTERN, Arc::new(move |r, p, c, s| handler.handle(r, p, c, s)))
247 }
248
249 pub fn group(mut self, pattern: &str, build: impl FnOnce(Group<S>) -> Group<S>) -> Self {
252 let inner = build(Group::new(&join_path(&self.prefix, pattern)));
253 self.routes.extend(inner.finish());
254 self
255 }
256
257 pub fn resource(mut self, path: &str, build: impl FnOnce(Resource<S>) -> Resource<S>) -> Self {
260 let resource = build(Resource::new(&join_path(&self.prefix, path)));
261 self.routes.extend(resource.finish());
262 self
263 }
264
265 pub(crate) fn finish(self) -> Vec<GroupRoute<SyncHandler<S>>> {
267 let guards: Arc<[Guard<S>]> = self.guards.into();
268 let layers: Arc<[Arc<dyn Middleware>]> = self.layers.into();
269 self.routes
270 .into_iter()
271 .map(|route| GroupRoute { handler: wrap_sync(route.handler, Arc::clone(&guards), Arc::clone(&layers)), ..route })
272 .collect()
273 }
274}
275
276pub struct Resource<S> {
279 group: Group<S>,
280 name: String,
281 actions: Vec<(&'static str, &'static str, &'static str, SyncHandler<S>)>,
282}
283
284macro_rules! resource_action {
285 ($(#[$doc:meta])* $fn:ident, $action:literal, $method:literal, $suffix:literal) => {
286 $(#[$doc])*
287 pub fn $fn<F>(mut self, handler: F) -> Self
288 where
289 F: Fn(&Request, &PathParams, &ConnectionInfo, &S) -> Response + Send + Sync + 'static,
290 {
291 self.actions.push(($action, $method, $suffix, Arc::new(move |r, p, c, s| handler(r, p, c, s))));
292 self
293 }
294 };
295}
296
297impl<S: Send + Sync + 'static> Resource<S> {
298 fn new(path: &str) -> Self {
299 Resource { name: resource_name(path), group: Group::new(path), actions: Vec::new() }
300 }
301
302 pub fn name(mut self, name: &str) -> Self {
304 self.name = name.to_string();
305 self
306 }
307
308 pub fn guard<G>(mut self, guard: G) -> Self
310 where
311 G: Fn(&Request, &ConnectionInfo, &S) -> Result<(), Response> + Send + Sync + 'static,
312 {
313 self.group = self.group.guard(guard);
314 self
315 }
316
317 pub fn wrap<M: Middleware + 'static>(mut self, layer: M) -> Self {
319 self.group = self.group.wrap(layer);
320 self
321 }
322
323 resource_action!(index, "index", "GET", "");
325 resource_action!(new_form, "new", "GET", "/new");
327 resource_action!(create, "create", "POST", "");
329 resource_action!(show, "show", "GET", "/{id}");
331 resource_action!(edit, "edit", "GET", "/{id}/edit");
333 resource_action!(update, "update", "PUT", "/{id}");
335 resource_action!(destroy, "destroy", "DELETE", "/{id}");
337
338 pub fn extra(mut self, build: impl FnOnce(Group<S>) -> Group<S>) -> Self {
341 let prefix = self.group.prefix.clone();
342 let inner = build(Group::new(&prefix));
343 self.group.routes.extend(inner.finish());
344 self
345 }
346
347 fn finish(mut self) -> Vec<GroupRoute<SyncHandler<S>>> {
348 let order = ["index", "new", "create", "show", "edit", "update", "destroy"];
350 self.actions.sort_by_key(|(action, ..)| order.iter().position(|a| a == action));
351 let mut group = self.group;
352 let mut extra = std::mem::take(&mut group.routes);
353 for (action, method, suffix, handler) in self.actions {
354 let pattern = join_path(&group.prefix, suffix);
355 let name = Some(format!("{}.{}", self.name, action));
356 if action == "update" {
357 group.routes.push(GroupRoute { method: "PATCH", pattern: pattern.clone(), name: None, handler: Arc::clone(&handler) });
358 }
359 group.routes.push(GroupRoute { method, pattern, name, handler });
360 }
361 group.routes.append(&mut extra);
362 group.finish()
363 }
364}
365
366#[cfg(feature = "http2")]
369pub use self::r#async::{AsyncGroup, AsyncResource};
370#[cfg(feature = "http2")]
371pub(crate) use self::r#async::AsyncHandlerFn;
372
373#[cfg(feature = "http2")]
374mod r#async {
375 use std::future::Future;
376 use std::pin::Pin;
377 use std::sync::Arc;
378
379 use super::{join_path, resource_name, Guard, GroupRoute};
380 use crate::request::Request;
381 use crate::response::Response;
382 use crate::router::PathParams;
383 use crate::server::ConnectionInfo;
384
385 pub(crate) type BoxFuture = Pin<Box<dyn Future<Output = Response> + Send + 'static>>;
386 pub(crate) type AsyncHandlerFn<S> = Arc<dyn Fn(Request, PathParams, ConnectionInfo, Arc<S>) -> BoxFuture + Send + Sync>;
388
389 fn wrap_async<S: Send + Sync + 'static>(handler: AsyncHandlerFn<S>, guards: Arc<[Guard<S>]>) -> AsyncHandlerFn<S> {
390 if guards.is_empty() {
391 return handler;
392 }
393 Arc::new(move |request, params, connection, state| {
394 for guard in guards.iter() {
395 if let Err(response) = guard(&request, &connection, &state) {
396 return Box::pin(async move { response });
397 }
398 }
399 handler(request, params, connection, state)
400 })
401 }
402
403 pub struct AsyncGroup<S> {
407 prefix: String,
408 guards: Vec<Guard<S>>,
409 routes: Vec<GroupRoute<AsyncHandlerFn<S>>>,
410 }
411
412 impl<S: Send + Sync + 'static> AsyncGroup<S> {
413 pub(crate) fn new(prefix: &str) -> Self {
414 AsyncGroup { prefix: prefix.to_string(), guards: Vec::new(), routes: Vec::new() }
415 }
416
417 fn push(mut self, method: &'static str, pattern: &str, handler: AsyncHandlerFn<S>) -> Self {
418 self.routes.push(GroupRoute { method, pattern: join_path(&self.prefix, pattern), name: None, handler });
419 self
420 }
421
422 fn boxed<F, Fut>(handler: F) -> AsyncHandlerFn<S>
423 where
424 F: Fn(Request, PathParams, ConnectionInfo, Arc<S>) -> Fut + Send + Sync + 'static,
425 Fut: Future<Output = Response> + Send + 'static,
426 {
427 Arc::new(move |r, p, c, s| Box::pin(handler(r, p, c, s)))
428 }
429
430 pub fn guard<G>(mut self, guard: G) -> Self
432 where
433 G: Fn(&Request, &ConnectionInfo, &S) -> Result<(), Response> + Send + Sync + 'static,
434 {
435 self.guards.push(Arc::new(guard));
436 self
437 }
438
439 pub fn name(mut self, name: &str) -> Self {
441 if let Some(route) = self.routes.last_mut() {
442 route.name = Some(name.to_string());
443 }
444 self
445 }
446
447 pub fn get<F, Fut>(self, pattern: &str, handler: F) -> Self
449 where
450 F: Fn(Request, PathParams, ConnectionInfo, Arc<S>) -> Fut + Send + Sync + 'static,
451 Fut: Future<Output = Response> + Send + 'static,
452 {
453 self.push("GET", pattern, Self::boxed(handler))
454 }
455
456 pub fn post<F, Fut>(self, pattern: &str, handler: F) -> Self
458 where
459 F: Fn(Request, PathParams, ConnectionInfo, Arc<S>) -> Fut + Send + Sync + 'static,
460 Fut: Future<Output = Response> + Send + 'static,
461 {
462 self.push("POST", pattern, Self::boxed(handler))
463 }
464
465 pub fn put<F, Fut>(self, pattern: &str, handler: F) -> Self
467 where
468 F: Fn(Request, PathParams, ConnectionInfo, Arc<S>) -> Fut + Send + Sync + 'static,
469 Fut: Future<Output = Response> + Send + 'static,
470 {
471 self.push("PUT", pattern, Self::boxed(handler))
472 }
473
474 pub fn patch<F, Fut>(self, pattern: &str, handler: F) -> Self
476 where
477 F: Fn(Request, PathParams, ConnectionInfo, Arc<S>) -> Fut + Send + Sync + 'static,
478 Fut: Future<Output = Response> + Send + 'static,
479 {
480 self.push("PATCH", pattern, Self::boxed(handler))
481 }
482
483 pub fn delete<F, Fut>(self, pattern: &str, handler: F) -> Self
485 where
486 F: Fn(Request, PathParams, ConnectionInfo, Arc<S>) -> Fut + Send + Sync + 'static,
487 Fut: Future<Output = Response> + Send + 'static,
488 {
489 self.push("DELETE", pattern, Self::boxed(handler))
490 }
491
492 pub fn route<H: crate::handler::AsyncHandler<S>>(self, handler: H) -> Self {
495 let handler = Arc::new(handler);
496 self.push(H::METHOD, H::PATTERN, Arc::new(move |r, p, c, s| handler.handle_async(r, p, c, s)))
497 }
498
499 pub fn group(mut self, pattern: &str, build: impl FnOnce(AsyncGroup<S>) -> AsyncGroup<S>) -> Self {
501 let inner = build(AsyncGroup::new(&join_path(&self.prefix, pattern)));
502 self.routes.extend(inner.finish());
503 self
504 }
505
506 pub fn resource(mut self, path: &str, build: impl FnOnce(AsyncResource<S>) -> AsyncResource<S>) -> Self {
508 let resource = build(AsyncResource::new(&join_path(&self.prefix, path)));
509 self.routes.extend(resource.finish());
510 self
511 }
512
513 pub(crate) fn finish(self) -> Vec<GroupRoute<AsyncHandlerFn<S>>> {
514 let guards: Arc<[Guard<S>]> = self.guards.into();
515 self.routes
516 .into_iter()
517 .map(|route| GroupRoute { handler: wrap_async(route.handler, Arc::clone(&guards)), ..route })
518 .collect()
519 }
520 }
521
522 pub struct AsyncResource<S> {
524 group: AsyncGroup<S>,
525 name: String,
526 actions: Vec<(&'static str, &'static str, &'static str, AsyncHandlerFn<S>)>,
527 }
528
529 macro_rules! async_resource_action {
530 ($(#[$doc:meta])* $fn:ident, $action:literal, $method:literal, $suffix:literal) => {
531 $(#[$doc])*
532 pub fn $fn<F, Fut>(mut self, handler: F) -> Self
533 where
534 F: Fn(Request, PathParams, ConnectionInfo, Arc<S>) -> Fut + Send + Sync + 'static,
535 Fut: Future<Output = Response> + Send + 'static,
536 {
537 self.actions.push(($action, $method, $suffix, AsyncGroup::<S>::boxed(handler)));
538 self
539 }
540 };
541 }
542
543 impl<S: Send + Sync + 'static> AsyncResource<S> {
544 fn new(path: &str) -> Self {
545 AsyncResource { name: resource_name(path), group: AsyncGroup::new(path), actions: Vec::new() }
546 }
547
548 pub fn name(mut self, name: &str) -> Self {
550 self.name = name.to_string();
551 self
552 }
553
554 pub fn guard<G>(mut self, guard: G) -> Self
556 where
557 G: Fn(&Request, &ConnectionInfo, &S) -> Result<(), Response> + Send + Sync + 'static,
558 {
559 self.group = self.group.guard(guard);
560 self
561 }
562
563 async_resource_action!(index, "index", "GET", "");
565 async_resource_action!(new_form, "new", "GET", "/new");
567 async_resource_action!(create, "create", "POST", "");
569 async_resource_action!(show, "show", "GET", "/{id}");
571 async_resource_action!(edit, "edit", "GET", "/{id}/edit");
573 async_resource_action!(update, "update", "PUT", "/{id}");
575 async_resource_action!(destroy, "destroy", "DELETE", "/{id}");
577
578 pub fn extra(mut self, build: impl FnOnce(AsyncGroup<S>) -> AsyncGroup<S>) -> Self {
580 let prefix = self.group.prefix.clone();
581 let inner = build(AsyncGroup::new(&prefix));
582 self.group.routes.extend(inner.finish());
583 self
584 }
585
586 fn finish(mut self) -> Vec<GroupRoute<AsyncHandlerFn<S>>> {
587 let order = ["index", "new", "create", "show", "edit", "update", "destroy"];
588 self.actions.sort_by_key(|(action, ..)| order.iter().position(|a| a == action));
589 let mut group = self.group;
590 let mut extra = std::mem::take(&mut group.routes);
591 for (action, method, suffix, handler) in self.actions {
592 let pattern = join_path(&group.prefix, suffix);
593 let name = Some(format!("{}.{}", self.name, action));
594 if action == "update" {
595 group.routes.push(GroupRoute { method: "PATCH", pattern: pattern.clone(), name: None, handler: Arc::clone(&handler) });
596 }
597 group.routes.push(GroupRoute { method, pattern, name, handler });
598 }
599 group.routes.append(&mut extra);
600 group.finish()
601 }
602 }
603}