Oregami
Repositories/oxedyne/fe2o3

oxedyne/fe2o3/fe2o3_text/tests/annealer_corpus/axum_router.rs

26.7 KiB, 1 run

created by r1870400018:11692, which is this file's identity for as long as the history lasts, whatever it is later renamed to

download · who wrote it · its history

1//! Routing between [`Service`]s and handlers.
2
3use self::{future::RouteFuture, not_found::NotFound, path_router::PathRouter};
4#[cfg(feature = "tokio")]
5use crate::extract::connect_info::IntoMakeServiceWithConnectInfo;
6#[cfg(feature = "matched-path")]
7use crate::extract::MatchedPath;
8use crate::{
9 body::{Body, HttpBody},
10 boxed::BoxedIntoRoute,
11 handler::Handler,
12 util::try_downcast,
13};
14use axum_core::{
15 extract::Request,
16 response::{IntoResponse, Response},
17};
18use std::{
19 convert::Infallible,
20 fmt,
21 marker::PhantomData,
22 sync::Arc,
23 task::{Context, Poll},
24};
25use tower::service_fn;
26use tower_layer::{layer_fn, Layer};
27use tower_service::Service;
28
29pub mod future;
30pub mod method_routing;
31
32mod into_make_service;
33mod method_filter;
34mod not_found;
35pub(crate) mod path_router;
36mod route;
37mod strip_prefix;
38pub(crate) mod url_params;
39
40#[cfg(test)]
41mod tests;
42
43pub use self::{into_make_service::IntoMakeService, method_filter::MethodFilter, route::Route};
44
45pub use self::method_routing::{
46 any, any_service, connect, connect_service, delete, delete_service, get, get_service, head,
47 head_service, on, on_service, options, options_service, patch, patch_service, post,
48 post_service, put, put_service, trace, trace_service, MethodRouter,
49};
50
51macro_rules! panic_on_err {
52 ($expr:expr) => {
53 match $expr {
54 Ok(x) => x,
55 Err(err) => panic!("{err}"),
56 }
57 };
58}
59
60const TAKE_ONCE_ROUTE_PANIC_MSG: &str =
61 "TakeOnceRoute called more than once; if this was not triggered by an intentional test, this should never happen. Please file an issue.";
62
63fn take_route_or_internal_error(service: &mut Option<Route>) -> Route {
64 service.take().unwrap_or_else(|| {
65 if cfg!(debug_assertions) {
66 panic!("{TAKE_ONCE_ROUTE_PANIC_MSG}");
67 }
68
69 Route::new(service_fn(|_req: Request| async move {
70 Ok::<_, Infallible>(http::StatusCode::INTERNAL_SERVER_ERROR.into_response())
71 }))
72 })
73}
74
75#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
76pub(crate) struct RouteId(usize);
77
78/// The router type for composing handlers and services.
79///
80/// `Router<S>` means a router that is _missing_ a state of type `S` to be able
81/// to handle requests. Thus, only `Router<()>` (i.e. without missing state) can
82/// be passed to [`serve`]. See [`Router::with_state`] for more details.
83///
84/// [`serve`]: crate::serve()
85#[must_use]
86pub struct Router<S = ()> {
87 inner: Arc<RouterInner<S>>,
88}
89
90impl<S> Clone for Router<S> {
91 fn clone(&self) -> Self {
92 Self {
93 inner: Arc::clone(&self.inner),
94 }
95 }
96}
97
98struct RouterInner<S> {
99 path_router: PathRouter<S>,
100 default_fallback: bool,
101 catch_all_fallback: Fallback<S>,
102}
103
104impl<S> Default for Router<S>
105where
106 S: Clone + Send + Sync + 'static,
107{
108 fn default() -> Self {
109 Self::new()
110 }
111}
112
113impl<S> fmt::Debug for Router<S> {
114 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
115 f.debug_struct("Router")
116 .field("path_router", &self.inner.path_router)
117 .field("default_fallback", &self.inner.default_fallback)
118 .field("catch_all_fallback", &self.inner.catch_all_fallback)
119 .finish()
120 }
121}
122
123pub(crate) const NEST_TAIL_PARAM: &str = "__private__axum_nest_tail_param";
124#[cfg(feature = "matched-path")]
125pub(crate) const NEST_TAIL_PARAM_CAPTURE: &str = "/{*__private__axum_nest_tail_param}";
126pub(crate) const FALLBACK_PARAM: &str = "__private__axum_fallback";
127pub(crate) const FALLBACK_PARAM_PATH: &str = "/{*__private__axum_fallback}";
128
129macro_rules! map_inner {
130 ( $self_:ident, $inner:pat_param => $expr:expr) => {
131 #[allow(redundant_semicolons)]
132 {
133 let $inner = $self_.into_inner();
134 Router {
135 inner: Arc::new($expr),
136 }
137 }
138 };
139}
140
141macro_rules! tap_inner {
142 ( $self_:ident, mut $inner:ident => { $($stmt:stmt)* } ) => {
143 #[allow(redundant_semicolons)]
144 {
145 let mut $inner = $self_.into_inner();
146 $($stmt)*;
147 Router {
148 inner: Arc::new($inner),
149 }
150 }
151 };
152}
153
154impl<S> Router<S>
155where
156 S: Clone + Send + Sync + 'static,
157{
158 /// Create a new `Router`.
159 ///
160 /// Unless you add additional routes this will respond with `404 Not Found` to
161 /// all requests.
162 pub fn new() -> Self {
163 Self {
164 inner: Arc::new(RouterInner {
165 path_router: Default::default(),
166 default_fallback: true,
167 catch_all_fallback: Fallback::Default(Route::new(NotFound)),
168 }),
169 }
170 }
171
172 fn into_inner(self) -> RouterInner<S> {
173 match Arc::try_unwrap(self.inner) {
174 Ok(inner) => inner,
175 Err(arc) => RouterInner {
176 path_router: arc.path_router.clone(),
177 default_fallback: arc.default_fallback,
178 catch_all_fallback: arc.catch_all_fallback.clone(),
179 },
180 }
181 }
182
183 #[doc = include_str!("../docs/routing/without_v07_checks.md")]
184 pub fn without_v07_checks(self) -> Self {
185 tap_inner!(self, mut this => {
186 this.path_router.without_v07_checks();
187 })
188 }
189
190 #[doc = include_str!("../docs/routing/route.md")]
191 #[track_caller]
192 pub fn route(self, path: &str, method_router: MethodRouter<S>) -> Self {
193 tap_inner!(self, mut this => {
194 panic_on_err!(this.path_router.route(path, method_router));
195 })
196 }
197
198 #[doc = include_str!("../docs/routing/route_service.md")]
199 pub fn route_service<T>(self, path: &str, service: T) -> Self
200 where
201 T: Service<Request, Error = Infallible> + Clone + Send + Sync + 'static,
202 T::Response: IntoResponse,
203 T::Future: Send + 'static,
204 {
205 let Err(service) = try_downcast::<Self, _>(service) else {
206 panic!(
207 "Invalid route: `Router::route_service` cannot be used with `Router`s. \
208 Use `Router::nest` instead"
209 );
210 };
211
212 tap_inner!(self, mut this => {
213 panic_on_err!(this.path_router.route_service(path, service));
214 })
215 }
216
217 #[doc = include_str!("../docs/routing/nest.md")]
218 #[doc(alias = "scope")] // Some other libs like actix-web use this term
219 #[track_caller]
220 pub fn nest(self, path: &str, router: Self) -> Self {
221 if path.is_empty() || path == "/" {
222 panic!("Nesting at the root is no longer supported. Use merge instead.");
223 }
224
225 let RouterInner {
226 path_router,
227 default_fallback: _,
228 // we don't need to inherit the catch-all fallback. It is only used for CONNECT
229 // requests with an empty path. If we were to inherit the catch-all fallback
230 // it would end up matching `/{path}/*` which doesn't match empty paths.
231 catch_all_fallback: _,
232 } = router.into_inner();
233
234 tap_inner!(self, mut this => {
235 panic_on_err!(this.path_router.nest(path, path_router));
236 })
237 }
238
239 /// Like [`nest`](Self::nest), but accepts an arbitrary `Service`.
240 #[track_caller]
241 pub fn nest_service<T>(self, path: &str, service: T) -> Self
242 where
243 T: Service<Request, Error = Infallible> + Clone + Send + Sync + 'static,
244 T::Response: IntoResponse,
245 T::Future: Send + 'static,
246 {
247 if path.is_empty() || path == "/" {
248 panic!("Nesting at the root is no longer supported. Use fallback_service instead.");
249 }
250
251 tap_inner!(self, mut this => {
252 panic_on_err!(this.path_router.nest_service(path, service));
253 })
254 }
255
256 #[doc = include_str!("../docs/routing/merge.md")]
257 #[track_caller]
258 pub fn merge<R>(self, other: R) -> Self
259 where
260 R: Into<Self>,
261 {
262 let other: Self = other.into();
263 let RouterInner {
264 path_router,
265 default_fallback,
266 catch_all_fallback,
267 } = other.into_inner();
268
269 map_inner!(self, mut this => {
270 match (this.default_fallback, default_fallback) {
271 // other has a default fallback
272 // use the one from other
273 (_, true) => {}
274 // this has default fallback, other has a custom fallback
275 (true, false) => {
276 this.default_fallback = false;
277 }
278 // both have a custom fallback, not allowed
279 (false, false) => {
280 panic!("Cannot merge two `Router`s that both have a fallback")
281 }
282 };
283
284 panic_on_err!(this.path_router.merge(path_router));
285
286 this.catch_all_fallback = this
287 .catch_all_fallback
288 .merge(catch_all_fallback)
289 .unwrap_or_else(|| panic!("Cannot merge two `Router`s that both have a fallback"));
290
291 this
292 })
293 }
294
295 #[doc = include_str!("../docs/routing/layer.md")]
296 pub fn layer<L>(self, layer: L) -> Self
297 where
298 L: Layer<Route> + Clone + Send + Sync + 'static,
299 L::Service: Service<Request> + Clone + Send + Sync + 'static,
300 <L::Service as Service<Request>>::Response: IntoResponse + 'static,
301 <L::Service as Service<Request>>::Error: Into<Infallible> + 'static,
302 <L::Service as Service<Request>>::Future: Send + 'static,
303 {
304 map_inner!(self, this => RouterInner {
305 path_router: this.path_router.layer(layer.clone()),
306 default_fallback: this.default_fallback,
307 catch_all_fallback: this.catch_all_fallback.map(|route| route.layer(layer)),
308 })
309 }
310
311 #[doc = include_str!("../docs/routing/route_layer.md")]
312 #[track_caller]
313 pub fn route_layer<L>(self, layer: L) -> Self
314 where
315 L: Layer<Route> + Clone + Send + Sync + 'static,
316 L::Service: Service<Request> + Clone + Send + Sync + 'static,
317 <L::Service as Service<Request>>::Response: IntoResponse + 'static,
318 <L::Service as Service<Request>>::Error: Into<Infallible> + 'static,
319 <L::Service as Service<Request>>::Future: Send + 'static,
320 {
321 map_inner!(self, this => RouterInner {
322 path_router: this.path_router.route_layer(layer),
323 default_fallback: this.default_fallback,
324 catch_all_fallback: this.catch_all_fallback,
325 })
326 }
327
328 /// True if the router currently has at least one route added.
329 #[must_use]
330 pub fn has_routes(&self) -> bool {
331 self.inner.path_router.has_routes()
332 }
333
334 #[track_caller]
335 #[doc = include_str!("../docs/routing/fallback.md")]
336 pub fn fallback<H, T>(self, handler: H) -> Self
337 where
338 H: Handler<T, S>,
339 T: 'static,
340 {
341 tap_inner!(self, mut this => {
342 this.catch_all_fallback =
343 Fallback::BoxedHandler(BoxedIntoRoute::from_handler(handler.clone()));
344 })
345 .fallback_endpoint(Endpoint::MethodRouter(any(handler)))
346 }
347
348 /// Add a fallback [`Service`] to the router.
349 ///
350 /// See [`Router::fallback`] for more details.
351 pub fn fallback_service<T>(self, service: T) -> Self
352 where
353 T: Service<Request, Error = Infallible> + Clone + Send + Sync + 'static,
354 T::Response: IntoResponse,
355 T::Future: Send + 'static,
356 {
357 let route = Route::new(service);
358 tap_inner!(self, mut this => {
359 this.catch_all_fallback = Fallback::Service(route.clone());
360 })
361 .fallback_endpoint(Endpoint::Route(route))
362 }
363
364 #[doc = include_str!("../docs/routing/method_not_allowed_fallback.md")]
365 #[allow(clippy::needless_pass_by_value)]
366 pub fn method_not_allowed_fallback<H, T>(self, handler: H) -> Self
367 where
368 H: Handler<T, S>,
369 T: 'static,
370 {
371 tap_inner!(self, mut this => {
372 this.path_router
373 .method_not_allowed_fallback(&handler);
374 })
375 }
376
377 /// Reset the fallback to its default.
378 ///
379 /// Useful to merge two routers with fallbacks, as [`merge`] doesn't allow
380 /// both routers to have an explicit fallback. Use this method to remove the
381 /// one you want to discard before merging.
382 ///
383 /// [`merge`]: Self::merge
384 pub fn reset_fallback(self) -> Self {
385 tap_inner!(self, mut this => {
386 this.default_fallback = true;
387 this.catch_all_fallback = Fallback::Default(Route::new(NotFound));
388 })
389 }
390
391 fn fallback_endpoint(self, endpoint: Endpoint<S>) -> Self {
392 // TODO make this better.
393 // We need the returned `Service` to be `Clone` and the function inside `service_fn` to be
394 // `FnMut` so instead of just using the owned service, we do this trick with `Option`. We
395 // know this will be called just once so it's fine. We're doing that so that we avoid one
396 // clone inside `oneshot_inner` so that the `Router` and subsequently the `State` is not
397 // cloned too much.
398 tap_inner!(self, mut this => {
399 _ = this.path_router.route_endpoint(
400 "/",
401 endpoint.clone().layer(
402 layer_fn(
403 |service: Route| {
404 let mut service = Some(service);
405 service_fn(
406 #[cfg_attr(not(feature = "matched-path"), allow(unused_mut))]
407 move |mut request: Request| {
408 #[cfg(feature = "matched-path")]
409 request.extensions_mut().remove::<MatchedPath>();
410 let route = take_route_or_internal_error(&mut service);
411 route.oneshot_inner_owned(request)
412 }
413 )
414 }
415 )
416 )
417 );
418
419 _ = this.path_router.route_endpoint(
420 FALLBACK_PARAM_PATH,
421 endpoint.layer(
422 layer_fn(
423 |service: Route| {
424 let mut service = Some(service);
425 service_fn(
426 #[cfg_attr(not(feature = "matched-path"), allow(unused_mut))]
427 move |mut request: Request| {
428 #[cfg(feature = "matched-path")]
429 request.extensions_mut().remove::<MatchedPath>();
430 let route = take_route_or_internal_error(&mut service);
431 route.oneshot_inner_owned(request)
432 }
433 )
434 }
435 )
436 )
437 );
438
439 this.default_fallback = false;
440 })
441 }
442
443 #[doc = include_str!("../docs/routing/with_state.md")]
444 pub fn with_state<S2>(self, state: S) -> Router<S2> {
445 map_inner!(self, this => RouterInner {
446 path_router: this.path_router.with_state(state.clone()),
447 default_fallback: this.default_fallback,
448 catch_all_fallback: this.catch_all_fallback.with_state(state),
449 })
450 }
451
452 pub(crate) fn call_with_state(&self, req: Request, state: S) -> RouteFuture<Infallible> {
453 let (req, state) = match self.inner.path_router.call_with_state(req, state) {
454 Ok(future) => return future,
455 Err((req, state)) => (req, state),
456 };
457
458 self.inner
459 .catch_all_fallback
460 .clone()
461 .call_with_state(req, state)
462 }
463
464 /// Convert the router into a borrowed [`Service`] with a fixed request body type, to aid type
465 /// inference.
466 ///
467 /// In some cases when calling methods from [`tower::ServiceExt`] on a [`Router`] you might get
468 /// type inference errors along the lines of
469 ///
470 /// ```not_rust
471 /// let response = router.ready().await?.call(request).await?;
472 /// ^^^^^ cannot infer type for type parameter `B`
473 /// ```
474 ///
475 /// This happens because `Router` implements [`Service`] with `impl<B> Service<Request<B>> for Router<()>`.
476 ///
477 /// For example:
478 ///
479 /// ```compile_fail
480 /// use axum::{
481 /// Router,
482 /// routing::get,
483 /// http::Request,
484 /// body::Body,
485 /// };
486 /// use tower::{Service, ServiceExt};
487 ///
488 /// # async fn async_main() -> Result<(), Box<dyn std::error::Error>> {
489 /// let mut router = Router::new().route("/", get(|| async {}));
490 /// let request = Request::new(Body::empty());
491 /// let response = router.ready().await?.call(request).await?;
492 /// # Ok(())
493 /// # }
494 /// ```
495 ///
496 /// Calling `Router::as_service` fixes that:
497 ///
498 /// ```
499 /// use axum::{
500 /// Router,
501 /// routing::get,
502 /// http::Request,
503 /// body::Body,
504 /// };
505 /// use tower::{Service, ServiceExt};
506 ///
507 /// # async fn async_main() -> Result<(), Box<dyn std::error::Error>> {
508 /// let mut router = Router::new().route("/", get(|| async {}));
509 /// let request = Request::new(Body::empty());
510 /// let response = router.as_service().ready().await?.call(request).await?;
511 /// # Ok(())
512 /// # }
513 /// ```
514 ///
515 /// This is mainly used when calling `Router` in tests. It shouldn't be necessary when running
516 /// the `Router` normally via [`Router::into_make_service`].
517 pub fn as_service<B>(&mut self) -> RouterAsService<'_, B, S> {
518 RouterAsService {
519 router: self,
520 _marker: PhantomData,
521 }
522 }
523
524 /// Convert the router into an owned [`Service`] with a fixed request body type, to aid type
525 /// inference.
526 ///
527 /// This is the same as [`Router::as_service`] instead it returns an owned [`Service`]. See
528 /// that method for more details.
529 #[must_use]
530 pub fn into_service<B>(self) -> RouterIntoService<B, S> {
531 RouterIntoService {
532 router: self,
533 _marker: PhantomData,
534 }
535 }
536}
537
538impl Router {
539 /// Convert this router into a [`MakeService`], that is a [`Service`] whose
540 /// response is another service.
541 ///
542 /// ```
543 /// use axum::{
544 /// routing::get,
545 /// Router,
546 /// };
547 ///
548 /// let app = Router::new().route("/", get(|| async { "Hi!" }));
549 ///
550 /// # async {
551 /// let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
552 /// axum::serve(listener, app).await;
553 /// # };
554 /// ```
555 ///
556 /// [`MakeService`]: tower::make::MakeService
557 #[must_use]
558 pub fn into_make_service(self) -> IntoMakeService<Self> {
559 // call `Router::with_state` such that everything is turned into `Route` eagerly
560 // rather than doing that per request
561 IntoMakeService::new(self.with_state(()))
562 }
563
564 #[doc = include_str!("../docs/routing/into_make_service_with_connect_info.md")]
565 #[cfg(feature = "tokio")]
566 #[must_use]
567 pub fn into_make_service_with_connect_info<C>(self) -> IntoMakeServiceWithConnectInfo<Self, C> {
568 // call `Router::with_state` such that everything is turned into `Route` eagerly
569 // rather than doing that per request
570 IntoMakeServiceWithConnectInfo::new(self.with_state(()))
571 }
572}
573
574// for `axum::serve(listener, router)`
575#[cfg(all(feature = "tokio", any(feature = "http1", feature = "http2")))]
576const _: () = {
577 use crate::serve;
578
579 impl<L> Service<serve::IncomingStream<'_, L>> for Router<()>
580 where
581 L: serve::Listener,
582 {
583 type Response = Self;
584 type Error = Infallible;
585 type Future = std::future::Ready<Result<Self::Response, Self::Error>>;
586
587 fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
588 Poll::Ready(Ok(()))
589 }
590
591 fn call(&mut self, _req: serve::IncomingStream<'_, L>) -> Self::Future {
592 // call `Router::with_state` such that everything is turned into `Route` eagerly
593 // rather than doing that per request
594 std::future::ready(Ok(self.clone().with_state(())))
595 }
596 }
597};
598
599impl<B> Service<Request<B>> for Router<()>
600where
601 B: HttpBody<Data = bytes::Bytes> + Send + 'static,
602 B::Error: Into<axum_core::BoxError>,
603{
604 type Response = Response;
605 type Error = Infallible;
606 type Future = RouteFuture<Infallible>;
607
608 #[inline]
609 fn poll_ready(&mut self, _: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
610 Poll::Ready(Ok(()))
611 }
612
613 #[inline]
614 fn call(&mut self, req: Request<B>) -> Self::Future {
615 let req = req.map(Body::new);
616 self.call_with_state(req, ())
617 }
618}
619
620/// A [`Router`] converted into a borrowed [`Service`] with a fixed body type.
621///
622/// See [`Router::as_service`] for more details.
623pub struct RouterAsService<'a, B, S = ()> {
624 router: &'a mut Router<S>,
625 _marker: PhantomData<fn(B)>,
626}
627
628impl<B> Service<Request<B>> for RouterAsService<'_, B, ()>
629where
630 B: HttpBody<Data = bytes::Bytes> + Send + 'static,
631 B::Error: Into<axum_core::BoxError>,
632{
633 type Response = Response;
634 type Error = Infallible;
635 type Future = RouteFuture<Infallible>;
636
637 #[inline]
638 fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
639 <Router as Service<Request<B>>>::poll_ready(self.router, cx)
640 }
641
642 #[inline]
643 fn call(&mut self, req: Request<B>) -> Self::Future {
644 self.router.call(req)
645 }
646}
647
648impl<B, S> fmt::Debug for RouterAsService<'_, B, S>
649where
650 S: fmt::Debug,
651{
652 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
653 f.debug_struct("RouterAsService")
654 .field("router", &self.router)
655 .finish()
656 }
657}
658
659/// A [`Router`] converted into an owned [`Service`] with a fixed body type.
660///
661/// See [`Router::into_service`] for more details.
662pub struct RouterIntoService<B, S = ()> {
663 router: Router<S>,
664 _marker: PhantomData<fn(B)>,
665}
666
667impl<B, S> Clone for RouterIntoService<B, S>
668where
669 Router<S>: Clone,
670{
671 fn clone(&self) -> Self {
672 Self {
673 router: self.router.clone(),
674 _marker: PhantomData,
675 }
676 }
677}
678
679impl<B> Service<Request<B>> for RouterIntoService<B, ()>
680where
681 B: HttpBody<Data = bytes::Bytes> + Send + 'static,
682 B::Error: Into<axum_core::BoxError>,
683{
684 type Response = Response;
685 type Error = Infallible;
686 type Future = RouteFuture<Infallible>;
687
688 #[inline]
689 fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
690 <Router as Service<Request<B>>>::poll_ready(&mut self.router, cx)
691 }
692
693 #[inline]
694 fn call(&mut self, req: Request<B>) -> Self::Future {
695 self.router.call(req)
696 }
697}
698
699impl<B, S> fmt::Debug for RouterIntoService<B, S>
700where
701 S: fmt::Debug,
702{
703 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
704 f.debug_struct("RouterIntoService")
705 .field("router", &self.router)
706 .finish()
707 }
708}
709
710enum Fallback<S, E = Infallible> {
711 Default(Route<E>),
712 Service(Route<E>),
713 BoxedHandler(BoxedIntoRoute<S, E>),
714}
715
716impl<S, E> Fallback<S, E>
717where
718 S: Clone,
719{
720 fn merge(self, other: Self) -> Option<Self> {
721 match (self, other) {
722 // If either are `Default`, return the opposite one.
723 (Self::Default(_), pick) | (pick, Self::Default(_)) => Some(pick),
724 // Otherwise, return None
725 _ => None,
726 }
727 }
728
729 fn map<F, E2>(self, f: F) -> Fallback<S, E2>
730 where
731 S: 'static,
732 E: 'static,
733 F: FnOnce(Route<E>) -> Route<E2> + Clone + Send + Sync + 'static,
734 E2: 'static,
735 {
736 match self {
737 Self::Default(route) => Fallback::Default(f(route)),
738 Self::Service(route) => Fallback::Service(f(route)),
739 Self::BoxedHandler(handler) => Fallback::BoxedHandler(handler.map(f)),
740 }
741 }
742
743 fn with_state<S2>(self, state: S) -> Fallback<S2, E> {
744 match self {
745 Self::Default(route) => Fallback::Default(route),
746 Self::Service(route) => Fallback::Service(route),
747 Self::BoxedHandler(handler) => Fallback::Service(handler.into_route(state)),
748 }
749 }
750
751 fn call_with_state(self, req: Request, state: S) -> RouteFuture<E> {
752 match self {
753 Self::Default(route) | Self::Service(route) => route.oneshot_inner_owned(req),
754 Self::BoxedHandler(handler) => {
755 let route = handler.into_route(state);
756 route.oneshot_inner_owned(req)
757 }
758 }
759 }
760
761 fn is_default(&self) -> bool {
762 matches!(self, Self::Default(..))
763 }
764}
765
766impl<S, E> Clone for Fallback<S, E> {
767 fn clone(&self) -> Self {
768 match self {
769 Self::Default(inner) => Self::Default(inner.clone()),
770 Self::Service(inner) => Self::Service(inner.clone()),
771 Self::BoxedHandler(inner) => Self::BoxedHandler(inner.clone()),
772 }
773 }
774}
775
776impl<S, E> fmt::Debug for Fallback<S, E> {
777 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
778 match self {
779 Self::Default(inner) => f.debug_tuple("Default").field(inner).finish(),
780 Self::Service(inner) => f.debug_tuple("Service").field(inner).finish(),
781 Self::BoxedHandler(_) => f.debug_tuple("BoxedHandler").finish(),
782 }
783 }
784}
785
786#[allow(clippy::large_enum_variant)]
787enum Endpoint<S> {
788 MethodRouter(MethodRouter<S>),
789 Route(Route),
790}
791
792impl<S> Endpoint<S>
793where
794 S: Clone + Send + Sync + 'static,
795{
796 fn layer<L>(self, layer: L) -> Self
797 where
798 L: Layer<Route> + Clone + Send + Sync + 'static,
799 L::Service: Service<Request> + Clone + Send + Sync + 'static,
800 <L::Service as Service<Request>>::Response: IntoResponse + 'static,
801 <L::Service as Service<Request>>::Error: Into<Infallible> + 'static,
802 <L::Service as Service<Request>>::Future: Send + 'static,
803 {
804 match self {
805 Self::MethodRouter(method_router) => Self::MethodRouter(method_router.layer(layer)),
806 Self::Route(route) => Self::Route(route.layer(layer)),
807 }
808 }
809}
810
811impl<S> Clone for Endpoint<S> {
812 fn clone(&self) -> Self {
813 match self {
814 Self::MethodRouter(inner) => Self::MethodRouter(inner.clone()),
815 Self::Route(inner) => Self::Route(inner.clone()),
816 }
817 }
818}
819
820impl<S> fmt::Debug for Endpoint<S> {
821 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
822 match self {
823 Self::MethodRouter(method_router) => {
824 f.debug_tuple("MethodRouter").field(method_router).finish()
825 }
826 Self::Route(route) => f.debug_tuple("Route").field(route).finish(),
827 }
828 }
829}
830
831#[test]
832fn traits() {
833 use crate::test_helpers::*;
834 assert_send::<Router<()>>();
835 assert_sync::<Router<()>>();
836 assert_send::<RouterAsService<'static, Body, ()>>();
837 assert_sync::<RouterAsService<'static, Body, ()>>();
838 assert_send::<RouterIntoService<Body, ()>>();
839 assert_sync::<RouterIntoService<Body, ()>>();
840}