axum/routing/
mod.rs

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