From ca7262d40e773e27a4d186f4c5f7d1dafae9c0b7 Mon Sep 17 00:00:00 2001 From: Tristan Druyen Date: Tue, 15 Apr 2025 15:10:17 +0200 Subject: [PATCH] Expand support to TRACE, CONNECT & any method --- examples/advanced/api/ping/route.rs | 12 +++++++++ src/lib.rs | 41 ++++++++++++++++++++--------- tests/expand/advanced.expanded.rs | 24 +++++++++++++++++ 3 files changed, 64 insertions(+), 13 deletions(-) create mode 100644 examples/advanced/api/ping/route.rs diff --git a/examples/advanced/api/ping/route.rs b/examples/advanced/api/ping/route.rs new file mode 100644 index 0000000..df7bc9a --- /dev/null +++ b/examples/advanced/api/ping/route.rs @@ -0,0 +1,12 @@ +use axum::response::Html; +use axum::response::IntoResponse; + +pub async fn get() -> impl IntoResponse { + Html("

GET Pong!

").into_response() +} + +// This tests that our macro generates the routes in the correct order +// as any is only allowable as a first route. +pub async fn any() -> impl IntoResponse { + Html("

ANY Pong!

").into_response() +} diff --git a/src/lib.rs b/src/lib.rs index 4dbe3ec..e4282b8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -54,7 +54,7 @@ //! //! ### HTTP Methods //! -//! The macro supports all standard HTTP methods: +//! The macro supports all standard HTTP methods as defined in RFC9110. //! - ```get``` //! - ```post``` //! - ```put``` @@ -62,6 +62,11 @@ //! - ```patch``` //! - ```head``` //! - ```options``` +//! - ```trace``` +//! - ```connect``` +//! +//! And additionally +//! - ```any```, which maches all methods //! //! ### Path Parameters //! @@ -189,7 +194,6 @@ impl ModuleDir { /// Cargo manifest directory /// * `state_type` - The type name of your application state that will be shared /// across all routes -/// #[allow(clippy::missing_panics_doc)] #[proc_macro_attribute] pub fn folder_router(attr: TokenStream, item: TokenStream) -> TokenStream { @@ -298,30 +302,41 @@ fn methods_for_route(route_path: &PathBuf) -> Vec<&'static str> { }; // Define HTTP methods we're looking for - let methods = ["get", "post", "put", "delete", "patch", "head", "options"]; + let allowed_methods = [ + "any", "get", "post", "put", "delete", "patch", "head", "options", "trace", "connect", + ]; let mut found_methods = Vec::new(); - // Examine each item in the file + // Collect all pub & async fn's for item in &file.items { if let Item::Fn(fn_item) = item { let fn_name = fn_item.sig.ident.to_string(); // Check if the function name is one of our HTTP methods - if let Some(&method) = methods.iter().find(|&&m| m == fn_name) { - // Check if the function is public - let is_public = matches!(fn_item.vis, Visibility::Public(_)); + // if let Some(&method) = methods.iter().find(|&&m| m == fn_name) { + // Check if the function is public + let is_public = matches!(fn_item.vis, Visibility::Public(_)); - // Check if the function is async - let is_async = fn_item.sig.asyncness.is_some(); + // Check if the function is async + let is_async = fn_item.sig.asyncness.is_some(); - if is_public && is_async { - found_methods.push(method); - } + if is_public && is_async { + found_methods.push(fn_name); } + // } } } - found_methods + // Iterate through methods to ensure consistent order + allowed_methods + .into_iter() + .filter(|elem| { + found_methods + .clone() + .into_iter() + .any(|method| method == *elem) + }) + .collect() } fn route_registrations( diff --git a/tests/expand/advanced.expanded.rs b/tests/expand/advanced.expanded.rs index 10d994b..bbd9439 100644 --- a/tests/expand/advanced.expanded.rs +++ b/tests/expand/advanced.expanded.rs @@ -51,6 +51,20 @@ mod __folder_router__myfolderrouter__examples_advanced_api { } } } + #[path = "ping"] + pub mod ping { + #[path = "route.rs"] + pub mod route { + use axum::response::Html; + use axum::response::IntoResponse; + pub async fn get() -> impl IntoResponse { + Html("

GET Pong!

").into_response() + } + pub async fn any() -> impl IntoResponse { + Html("

ANY Pong!

").into_response() + } + } + } #[path = "users"] pub mod users { #[path = "route.rs"] @@ -99,6 +113,16 @@ impl MyFolderRouter { __folder_router__myfolderrouter__examples_advanced_api::files::route::post, ), ); + router = router + .route( + "/ping", + axum::routing::any( + __folder_router__myfolderrouter__examples_advanced_api::ping::route::any, + ) + .get( + __folder_router__myfolderrouter__examples_advanced_api::ping::route::get, + ), + ); router = router .route( "/",