Skip to content

Commit ee4727b

Browse files
authored
Add macro to compile time check if a path is valid (#3288)
1 parent 62470bd commit ee4727b

File tree

4 files changed

+53
-0
lines changed

4 files changed

+53
-0
lines changed

Cargo.lock

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

axum-extra/CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning].
88
# Unreleased
99

1010
- **fixed:** Fix a broken link in the documentation of `ErasedJson` ([#3186])
11+
- **added:** Add `vpath!` for compile time path verification on static paths. ([#3288])
1112

1213
[#3186]: https://github.com/tokio-rs/axum/pull/3186
1314

axum-extra/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ http-body = "1.0.0"
5858
http-body-util = "0.1.0"
5959
mime = "0.3"
6060
pin-project-lite = "0.2"
61+
rustversion = "1.0.9"
6162
serde = "1.0"
6263
tower = { version = "0.5.2", default-features = false, features = ["util"] }
6364
tower-layer = "0.3"

axum-extra/src/routing/mod.rs

+50
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,56 @@ pub use axum_macros::TypedPath;
2525
#[cfg(feature = "typed-routing")]
2626
pub use self::typed::{SecondElementIs, TypedPath};
2727

28+
// Validates a path at compile time, used with the vpath macro.
29+
#[rustversion::since(1.80)]
30+
#[doc(hidden)]
31+
pub const fn __private_validate_static_path(path: &'static str) -> &'static str {
32+
if path.is_empty() {
33+
panic!("Paths must start with a `/`. Use \"/\" for root routes")
34+
}
35+
if path.as_bytes()[0] != b'/' {
36+
panic!("Paths must start with /");
37+
}
38+
path
39+
}
40+
41+
/// This macro aborts compilation if the path is invalid.
42+
///
43+
/// This example will fail to compile:
44+
///
45+
/// ```compile_fail
46+
/// use axum::routing::{Router, get};
47+
/// use axum_extra::vpath;
48+
///
49+
/// let router = axum::Router::<()>::new()
50+
/// .route(vpath!("invalid_path"), get(root))
51+
/// .to_owned();
52+
///
53+
/// async fn root() {}
54+
/// ```
55+
///
56+
/// This one will compile without problems:
57+
///
58+
/// ```no_run
59+
/// use axum::routing::{Router, get};
60+
/// use axum_extra::vpath;
61+
///
62+
/// let router = axum::Router::<()>::new()
63+
/// .route(vpath!("/valid_path"), get(root))
64+
/// .to_owned();
65+
///
66+
/// async fn root() {}
67+
/// ```
68+
///
69+
/// This macro is available only on rust versions 1.80 and above.
70+
#[rustversion::since(1.80)]
71+
#[macro_export]
72+
macro_rules! vpath {
73+
($e:expr) => {
74+
const { $crate::routing::__private_validate_static_path($e) }
75+
};
76+
}
77+
2878
/// Extension trait that adds additional methods to [`Router`].
2979
pub trait RouterExt<S>: sealed::Sealed {
3080
/// Add a typed `GET` route to the router.

0 commit comments

Comments
 (0)