Struct PathPattern
pub struct PathPattern { /* private fields */ }net only.Expand description
A compiled path pattern.
Construct via PathPattern::new / new_with_opts
and test paths with is_match / captures.
§Syntax
A pattern is split on / into segments. The only metacharacters are {,
} and ?; everything else (*, :, ., +, …) is a literal. Within a
segment:
- literal text must equal the (decoded) path segment value;
{name}captures a non-empty run undername: a whole segment when alone ({id}), or the run bounded by surrounding literals when affixed ({pkg}.jsoncaptures the part before.json,v{ver}-rcthe part between);{}is an anonymous non-empty wildcard run, not captured ({}.txt);?makes the immediately preceding element optional (zero-or-one):a?is an optionala,{}?an optional run,{name}?an optional capture, and a trailing/?an optional trailing slash. A whole segment made only of{name}?or{}?is itself optional, so/foo/{name}?/barmatches/foo/john/bar,/foo//bar, and/foo/bar;{*}, as a whole segment, is an anonymous catch-all matching one or more path segments, available ‘/’-joined and decoded viaPathCaptures::glob. It may appear in the middle of a pattern;{*name}, as a whole segment, is the named catch-all: same 1+ segment match as{*}, but the run is recorded undername(read back, ‘/’-joined and decoded, viaPathCaptures::get). So{name}stays within a segment;{*name}spans segments.
An unclosed {, or a brace group whose body isn’t a valid token, is taken
literally. {*}/{*name} are catch-alls only as a whole segment.
Trailing slash is explicit: /a matches only /a, /a/ matches only
/a/, and /a/? matches both.
use rama_net::uri::{PathPattern, PathRef};
let pat = PathPattern::new("/p2/{vendor}/{pkg}.json");
let caps = pat.captures(PathRef::from_raw_str("/p2/acme/widget.json")).unwrap();
assert_eq!(caps.get("vendor"), Some("acme"));
assert_eq!(caps.get("pkg"), Some("widget"));
assert!(pat.captures(PathRef::from_raw_str("/p2/acme/widget.txt")).is_none());
let assets = PathPattern::new("/assets/{*}");
assert!(assets.is_match(PathRef::from_raw_str("/assets/css/app.css")));
assert!(!assets.is_match(PathRef::from_raw_str("/assets")));
// `{*name}` is the named catch-all (read back via `get`).
let files = PathPattern::new("/files/{*rest}");
let caps = files.captures(PathRef::from_raw_str("/files/a/b/c.txt")).unwrap();
assert_eq!(caps.get("rest"), Some("a/b/c.txt"));Implementations§
§impl PathPattern
impl PathPattern
pub fn new(pattern: impl IntoUriComponent) -> PathPattern
pub fn new(pattern: impl IntoUriComponent) -> PathPattern
Compile a path pattern. Infallible: anything not a recognized meta token is a literal.
use rama_net::uri::{PathPattern, PathRef};
let pat = PathPattern::new("/backend-api/codex/responses");
assert!(pat.is_match(PathRef::from_raw_str("/backend-api/codex/responses")));
assert!(!pat.is_match(PathRef::from_raw_str("/backend-api/codex")));pub fn new_with_opts(
pattern: impl IntoUriComponent,
opts: PathMatchOptions,
) -> PathPattern
pub fn new_with_opts( pattern: impl IntoUriComponent, opts: PathMatchOptions, ) -> PathPattern
new with explicit PathMatchOptions. The matcher
honors ignore_ascii_case and percent_decode; partial is
irrelevant and ignored.
use rama_net::uri::{PathMatchOptions, PathPattern, PathRef};
let opts = PathMatchOptions {
ignore_ascii_case: true,
..Default::default()
};
let pat = PathPattern::new_with_opts("/api/v2", opts);
assert!(pat.is_match(PathRef::from_raw_str("/API/v2")));pub fn new_prefix(pattern: impl IntoUriComponent) -> PathPattern
pub fn new_prefix(pattern: impl IntoUriComponent) -> PathPattern
Compile a prefix matcher: the pattern must match a leading run of the
path’s segments; any trailing segments and the path’s trailing slash are
ignored. So /api matches /api, /api/, and /api/users — but not
/apixyz (segments are matched whole).
use rama_net::uri::{PathPattern, PathRef};
let api = PathPattern::new_prefix("/api");
assert!(api.is_match(PathRef::from_raw_str("/api")));
assert!(api.is_match(PathRef::from_raw_str("/api/users/42")));
assert!(!api.is_match(PathRef::from_raw_str("/apixyz")));pub fn new_prefix_with_opts(
pattern: impl IntoUriComponent,
opts: PathMatchOptions,
) -> PathPattern
pub fn new_prefix_with_opts( pattern: impl IntoUriComponent, opts: PathMatchOptions, ) -> PathPattern
new_prefix with explicit PathMatchOptions.
pub fn segment_kinds(&self) -> impl ExactSizeIterator
pub fn segment_kinds(&self) -> impl ExactSizeIterator
The kind of each /-delimited pattern segment,
in order — so callers can classify segments (literal vs dynamic vs
catch-all) straight from the compiled pattern instead of re-parsing the
syntax. A bare-root pattern (/) yields an empty iterator.
use rama_net::uri::{PathPattern, PathPatternSegmentKind as K};
let kinds: Vec<_> = PathPattern::new("/users/{id}/{*rest}").segment_kinds().collect();
assert_eq!(kinds, [K::Literal, K::Dynamic, K::CatchAll]);
// An invalid catch-all body is a literal, exactly as the matcher treats it.
let kinds: Vec<_> = PathPattern::new("/api/{*bad name}").segment_kinds().collect();
assert_eq!(kinds, [K::Literal, K::Literal]);pub fn segment_specificity(&self) -> impl ExactSizeIterator
pub fn segment_specificity(&self) -> impl ExactSizeIterator
Specificity metadata for each /-delimited pattern segment, in order.
This is a richer version of segment_kinds for
callers that need stable precedence among overlapping dynamic patterns.
use rama_net::uri::{PathPattern, PathPatternSegmentKind as K};
let specs: Vec<_> = PathPattern::new("/files/{name}.json")
.segment_specificity()
.collect();
assert_eq!(specs[0].kind, K::Literal);
assert_eq!(specs[1].kind, K::Dynamic);
assert_eq!(specs[1].literal_bytes, 5);
assert_eq!(specs[1].dynamic_parts, 1);pub fn is_match(&self, path: PathRef<'_>) -> bool
pub fn is_match(&self, path: PathRef<'_>) -> bool
true when path matches. Allocation-free when the pattern has no
captures and no catch-all.
use rama_net::uri::{PathPattern, PathRef};
let pat = PathPattern::new("/files/{}.txt");
assert!(pat.is_match(PathRef::from_raw_str("/files/readme.txt")));
assert!(!pat.is_match(PathRef::from_raw_str("/files/readme.md")));pub fn captures<'p>(&self, path: PathRef<'p>) -> Option<PathCaptures<'_, 'p>>
pub fn captures<'p>(&self, path: PathRef<'p>) -> Option<PathCaptures<'_, 'p>>
Match and return captured values, or None when path doesn’t
match. Uses inline storage for the common small number of bindings.
use rama_net::uri::{PathPattern, PathRef};
let pat = PathPattern::new("/simple/{name}/?");
let caps = pat.captures(PathRef::from_raw_str("/simple/requests")).unwrap();
assert_eq!(caps.get("name"), Some("requests"));Trait Implementations§
§impl Clone for PathPattern
impl Clone for PathPattern
§fn clone(&self) -> PathPattern
fn clone(&self) -> PathPattern
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read more§impl Debug for PathPattern
impl Debug for PathPattern
impl Eq for PathPattern
§impl Hash for PathPattern
impl Hash for PathPattern
§impl PartialEq for PathPattern
impl PartialEq for PathPattern
Auto Trait Implementations§
impl Freeze for PathPattern
impl RefUnwindSafe for PathPattern
impl Send for PathPattern
impl Sync for PathPattern
impl Unpin for PathPattern
impl UnsafeUnpin for PathPattern
impl UnwindSafe for PathPattern
Blanket Implementations§
§impl<'a, T, E> AsTaggedExplicit<'a, E> for Twhere
T: 'a,
impl<'a, T, E> AsTaggedExplicit<'a, E> for Twhere
T: 'a,
§impl<'a, T, E> AsTaggedImplicit<'a, E> for Twhere
T: 'a,
impl<'a, T, E> AsTaggedImplicit<'a, E> for Twhere
T: 'a,
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
§fn equivalent(&self, key: &K) -> bool
fn equivalent(&self, key: &K) -> bool
key and return true if they are equal.§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
§fn equivalent(&self, key: &K) -> bool
fn equivalent(&self, key: &K) -> bool
§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
§fn equivalent(&self, key: &K) -> bool
fn equivalent(&self, key: &K) -> bool
§impl<T> FutureExt for T
impl<T> FutureExt for T
§fn with_context(self, otel_cx: Context) -> WithContext<Self> ⓘ
fn with_context(self, otel_cx: Context) -> WithContext<Self> ⓘ
§fn with_current_context(self) -> WithContext<Self> ⓘ
fn with_current_context(self) -> WithContext<Self> ⓘ
§impl<T> Instrument for T
impl<T> Instrument for T
§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more§impl<T> IntoRequest<T> for T
impl<T> IntoRequest<T> for T
§fn into_request(self) -> Request<T>
fn into_request(self) -> Request<T>
T in a rama_grpc::Request§impl<T> Pointable for T
impl<T> Pointable for T
§impl<T> PolicyExt for Twhere
T: ?Sized,
impl<T> PolicyExt for Twhere
T: ?Sized,
§fn and<P, B, E>(self, other: P) -> And<T, P>
fn and<P, B, E>(self, other: P) -> And<T, P>
Policy that returns Action::Follow only if self and other return
Action::Follow. Read more§impl<T, U> RamaTryFrom<T> for Uwhere
U: TryFrom<T>,
impl<T, U> RamaTryFrom<T> for Uwhere
U: TryFrom<T>,
type Error = <U as TryFrom<T>>::Error
fn rama_try_from(value: T) -> Result<U, <U as RamaTryFrom<T>>::Error>
§impl<T, U, CrateMarker> RamaTryInto<U, CrateMarker> for Twhere
U: RamaTryFrom<T, CrateMarker>,
impl<T, U, CrateMarker> RamaTryInto<U, CrateMarker> for Twhere
U: RamaTryFrom<T, CrateMarker>,
type Error = <U as RamaTryFrom<T, CrateMarker>>::Error
fn rama_try_into(self) -> Result<U, <U as RamaTryFrom<T, CrateMarker>>::Error>
impl<T> Read<Exclusive, BecauseExclusive> for Twhere
T: ?Sized,
§impl<V, F> ValueFormatter<&V> for F
impl<V, F> ValueFormatter<&V> for F
§fn format_value(writer: impl ValueWriter, value: &&V)
fn format_value(writer: impl ValueWriter, value: &&V)
value to writer§impl<V, F> ValueFormatter<Arc<V>> for F
impl<V, F> ValueFormatter<Arc<V>> for F
§fn format_value(writer: impl ValueWriter, value: &Arc<V>)
fn format_value(writer: impl ValueWriter, value: &Arc<V>)
value to writer§impl<V, F> ValueFormatter<Box<V>> for F
impl<V, F> ValueFormatter<Box<V>> for F
§fn format_value(writer: impl ValueWriter, value: &Box<V>)
fn format_value(writer: impl ValueWriter, value: &Box<V>)
value to writer§impl<V, F> ValueFormatter<Cow<'_, V>> for F
impl<V, F> ValueFormatter<Cow<'_, V>> for F
§fn format_value(writer: impl ValueWriter, value: &Cow<'_, V>)
fn format_value(writer: impl ValueWriter, value: &Cow<'_, V>)
value to writer§impl<V, F> ValueFormatter<Option<V>> for Fwhere
F: ValueFormatter<V> + ?Sized,
impl<V, F> ValueFormatter<Option<V>> for Fwhere
F: ValueFormatter<V> + ?Sized,
§fn format_value(writer: impl ValueWriter, value: &Option<V>)
fn format_value(writer: impl ValueWriter, value: &Option<V>)
value to writer