mirror of
https://github.com/tokio-rs/axum.git
synced 2026-08-28 00:00:20 +02:00
Support affixed typed path captures (#3782)
This commit is contained in:
@@ -362,8 +362,7 @@ fn format_str_from_path(segments: &[Segment]) -> String {
|
||||
Segment::Capture(capture, _) => format!("{{{capture}}}"),
|
||||
Segment::Static(segment) => segment.to_owned(),
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
.join("/")
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn captures_from_path(segments: &[Segment]) -> Vec<syn::Ident> {
|
||||
@@ -387,23 +386,58 @@ fn parse_path(path: &LitStr) -> syn::Result<Vec<Segment>> {
|
||||
return Err(syn::Error::new_spanned(path, "paths must start with a `/`"));
|
||||
}
|
||||
|
||||
path.value()
|
||||
.split('/')
|
||||
.map(|segment| {
|
||||
if let Some(capture) = segment
|
||||
.strip_prefix('{')
|
||||
.and_then(|segment| segment.strip_suffix('}'))
|
||||
.and_then(|segment| {
|
||||
(!segment.starts_with('{') && !segment.ends_with('}')).then_some(segment)
|
||||
})
|
||||
.map(|capture| capture.strip_prefix('*').unwrap_or(capture))
|
||||
{
|
||||
Ok(Segment::Capture(capture.to_owned(), path.span()))
|
||||
} else {
|
||||
Ok(Segment::Static(segment.to_owned()))
|
||||
let mut segments = Vec::new();
|
||||
let mut rest = value.as_str();
|
||||
|
||||
while let Some(start) = find_first_not_double(b'{', rest.as_bytes()) {
|
||||
if start > 0 {
|
||||
segments.push(Segment::Static(rest[..start].to_owned()));
|
||||
}
|
||||
|
||||
rest = &rest[start + 1..];
|
||||
|
||||
if let Some(end) = rest.find('}') {
|
||||
let capture = &rest[..end];
|
||||
if capture.is_empty() || capture.contains('{') {
|
||||
return Err(syn::Error::new_spanned(path, "invalid capture in path"));
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
|
||||
segments.push(Segment::Capture(
|
||||
capture.strip_prefix('*').unwrap_or(capture).to_owned(),
|
||||
path.span(),
|
||||
));
|
||||
|
||||
rest = &rest[end + 1..];
|
||||
} else {
|
||||
segments.push(Segment::Static(format!("{{{rest}")));
|
||||
rest = "";
|
||||
}
|
||||
}
|
||||
|
||||
if !rest.is_empty() {
|
||||
segments.push(Segment::Static(rest.to_owned()));
|
||||
}
|
||||
|
||||
Ok(segments)
|
||||
}
|
||||
|
||||
fn find_first_not_double(needle: u8, haystack: &[u8]) -> Option<usize> {
|
||||
let mut possible_capture = 0;
|
||||
while let Some(index) = haystack
|
||||
.get(possible_capture..)
|
||||
.and_then(|haystack| haystack.iter().position(|byte| byte == &needle))
|
||||
{
|
||||
let index = index + possible_capture;
|
||||
|
||||
if haystack.get(index + 1) == Some(&needle) {
|
||||
possible_capture = index + 2;
|
||||
continue;
|
||||
}
|
||||
|
||||
return Some(index);
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
enum Segment {
|
||||
|
||||
Reference in New Issue
Block a user