1#![doc = include_str!("../RESOLVE.md")]
45#![doc = include_str!("../ROUTER.md")]
47
48#[doc(hidden)]
51pub fn route_resolver<R: crate::__private::Router, T>(
52 router: R,
53 params: impl crate::__private::RouteParameters<T>,
54) -> Result<String, crate::__private::RouteResolverError> {
55 router.resolve_route(params.parameters())
56}
57
58#[doc(inline)]
59pub use axum_routes_macros::{router, routes};
60
61#[doc = include_str!("../RESOLVE.md")]
64#[macro_export]
66macro_rules! resolve {
67 ($route:expr) => {
68 $crate::route_resolver($route, ())
69 };
70 ($route:expr, $($pp:ident),+) => {
71 $crate::route_resolver($route, ($($pp,)*))
72 };
73 ($route:expr, $($pp:literal),+) => {
74 $crate::route_resolver($route, ($($pp,)*))
75 };
76}
77
78#[doc(hidden)]
81pub mod __private {
82 #[doc(hidden)]
85 #[allow(missing_debug_implementations)]
86 pub struct AssertFieldIsRouter<T: crate::__private::Router + ?Sized> {
87 pub _field: core::marker::PhantomData<T>,
88 }
89
90 #[doc(hidden)]
91 #[derive(thiserror::Error, Debug)]
92 pub enum RouteResolverError {
93 #[error("parameter mismatch")]
94 ParametersMismatch,
95 }
96
97 #[doc(hidden)]
99 pub trait Router {
100 fn routes(
102 customize: &std::collections::HashMap<&'static str, crate::__private::RouteCustomizer>,
103 ) -> axum::Router;
104
105 fn resolve_route(
107 &self,
108 params: Vec<String>,
109 ) -> Result<String, crate::__private::RouteResolverError>;
110 }
111
112 #[doc(hidden)]
115 pub trait RouteParameters<T>: Sized {
116 fn parameters(&self) -> Vec<String>;
117 }
118
119 impl RouteParameters<()> for () {
121 fn parameters(&self) -> Vec<String> {
122 Vec::new()
123 }
124 }
125
126 macro_rules! impl_route_parameters {
127 ($($ty:ident),+) => {
128
129 #[allow(non_snake_case)]
130 impl<$($ty,)*> $crate::__private::RouteParameters<($($ty,)*)> for ($($ty,)*)
131 where
132 $( $ty: ToString, )*
133 {
134 fn parameters(&self) -> Vec<String> {
135 let ($($ty,)*) = self;
136 Vec::from([
137 $( $ty.to_string(), )*
138 ])
139 }
140 }
141
142 };
143}
144
145 impl_route_parameters!(A);
146 impl_route_parameters!(A, B);
147 impl_route_parameters!(A, B, C);
148 impl_route_parameters!(A, B, C, D);
149 impl_route_parameters!(A, B, C, D, E);
150 impl_route_parameters!(A, B, C, D, E, F);
151 impl_route_parameters!(A, B, C, D, E, F, G);
152 impl_route_parameters!(A, B, C, D, E, F, G, H);
153 impl_route_parameters!(A, B, C, D, E, F, G, H, I);
154 impl_route_parameters!(A, B, C, D, E, F, G, H, I, J);
155
156 #[doc(hidden)]
159 pub enum RouteCustomizer {
160 Router(Box<dyn Fn(axum::Router) -> axum::Router>),
161 MethodRouter(Box<dyn Fn(axum::routing::MethodRouter) -> axum::routing::MethodRouter>),
162 }
163
164 impl RouteCustomizer {
165 pub fn customize_router(&self, router: axum::Router) -> axum::Router {
166 if let Self::Router(call) = self {
167 (call)(router)
168 } else {
169 panic!("should not be called on MethodRouter");
170 }
171 }
172
173 pub fn customize_route(
174 &self,
175 route: axum::routing::MethodRouter,
176 ) -> axum::routing::MethodRouter {
177 if let Self::MethodRouter(call) = self {
178 (call)(route)
179 } else {
180 panic!("should not be called on Router");
181 }
182 }
183 }
184}