diff --git a/Cargo.lock b/Cargo.lock index 2fb88ec..50e3742 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -176,6 +176,7 @@ version = "0.2.0" dependencies = [ "axum", "http", + "itertools", "serde", "specifications", ] @@ -734,6 +735,15 @@ version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" +[[package]] +name = "itertools" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.15" diff --git a/lib/servers/axum-spec/Cargo.toml b/lib/servers/axum-spec/Cargo.toml index 53d09e2..bce759f 100644 --- a/lib/servers/axum-spec/Cargo.toml +++ b/lib/servers/axum-spec/Cargo.toml @@ -13,6 +13,7 @@ description = "Pseudo-server that defines the API endpoint locations, methods an axum = { version = "0.8.0", optional = true } http = "1.0.0" serde = { version = "1.0.184", features = ["derive"] } +itertools = "0.14.0" specifications = { path = "../../spec" } diff --git a/lib/servers/axum-spec/src/lib.rs b/lib/servers/axum-spec/src/lib.rs index 45e352d..58cd8ea 100644 --- a/lib/servers/axum-spec/src/lib.rs +++ b/lib/servers/axum-spec/src/lib.rs @@ -18,8 +18,6 @@ use std::borrow::Cow; use std::collections::HashMap; #[cfg(feature = "axum")] use std::convert::Infallible; -use std::ffi::OsString; -use std::path::PathBuf; #[cfg(feature = "axum")] use axum::handler::Handler; @@ -28,6 +26,7 @@ use axum::routing::MethodRouter; #[cfg(feature = "axum")] use axum::routing::method_routing::{delete, get, post, put}; use http::Method; +use itertools::Itertools as _; use serde::{Deserialize, Serialize}; use specifications::metadata::{AttachedMetadata, Metadata, User}; @@ -85,38 +84,29 @@ impl EndpointPath { /// - the number of arguments given does not match the number of arguments in the path. #[inline] #[track_caller] - pub fn instantiated_path(&self, args: impl IntoIterator) -> Cow<'static, str> { + pub fn instantiated_path<'a, S: AsRef>(&self, args: impl IntoIterator) -> Cow<'static, str> { let mut args = args.into_iter(); - if !self.path.contains("/:") { - // Ensure there aren't any arguments - if args.next().is_some() { - panic!("Arguments given for path {:?} which has no arguments", self.path); - } - return Cow::Borrowed(self.path); - } - let mut i: usize = 0; - let path: PathBuf = PathBuf::from(self.path) - .iter() - .map(|com| { - // SAFETY: It came from a string, so why wouldn't be UTF-8??? (famous last words) - let scom: &str = unsafe { com.to_str().unwrap_unchecked() }; - if scom.starts_with(":") { - let res = OsString::from( - args.next().unwrap_or_else(|| panic!("Not enough arguments given for path {:?} (got {})", self.path, i)).to_string(), - ); - i += 1; + let mut replace_count: usize = 0; + let path = self + .path + .split("/") + .map(|component| { + if component.starts_with("{") && component.ends_with("}") { + let res = args.next().unwrap_or_else(|| panic!("Not enough arguments given for path {:?} (got {replace_count})", self.path)); + replace_count += 1; res } else { - com.to_os_string() + component } }) - .collect(); + .join("/"); + // Assert none are left if args.next().is_some() { panic!("Too many arguments given for path {:?} which has no arguments", self.path); } - // SAFETY: It came from a string, and we only put strings in there, so why wouldn't be UTF-8??? (famous last words) - Cow::Owned(unsafe { path.into_os_string().into_string().unwrap_unchecked() }) + + if replace_count == 0 { Cow::Borrowed(self.path) } else { Cow::Owned(path) } } }