///|
/// A single segment of a pre-compiled route pattern.
pub(all) enum RouteSegment {
/// A literal path segment that must match exactly (e.g. "api", "users")
Static(String)
/// A named parameter that captures a single segment (e.g. ":id")
Param(String)
/// A single-level wildcard that captures one segment (e.g. "*")
Wildcard
/// A multi-level wildcard that captures zero or more segments (e.g. "**")
GlobStar
} derive(Eq)
///|
/// A pre-compiled route pattern, parsed once at registration time.
pub struct CompiledRoute {
/// The original template string (for debugging/display)
template : String
/// Pre-parsed segments (avoids re-splitting on every request)
segments : Array[RouteSegment]
/// True if the route is static (no parameters or wildcards)
is_static : Bool
}
///|
/// Compiles a route template string into a `CompiledRoute`.
pub fn CompiledRoute::compile(template : String) -> CompiledRoute {
let parts = template.split("/")
let segments : Array[RouteSegment] = []
let mut is_static = true
for part in parts {
if part == "**" {
segments.push(GlobStar)
is_static = false
} else if part == "*" {
segments.push(Wildcard)
is_static = false
} else if part.view() lexmatch? (":", param_name) {
segments.push(Param(param_name.to_string()))
is_static = false
} else {
segments.push(Static(part.to_string()))
}
}
{ template, segments, is_static }
}
///|
/// Matches a compiled route against a request path, returning extracted parameters or None.
pub fn CompiledRoute::match_path(
self : CompiledRoute,
path : String,
) -> Map[String, StringView]? {
// Static paths: direct comparison (fastest path)
if self.is_static {
return if self.template == path { Some({}) } else { None }
}
let path_parts = path.split("/").collect()
match_compiled_segments(self.segments, path_parts, 0, 0, {})
}
///|
fn match_compiled_segments(
segments : Array[RouteSegment],
path_parts : Array[StringView],
seg_idx : Int,
path_idx : Int,
params : Map[String, StringView],
) -> Map[String, StringView]? {
// Both exhausted: match succeeded
if seg_idx >= segments.length() && path_idx >= path_parts.length() {
return Some(params)
}
// Template exhausted but path remains: no match
if seg_idx >= segments.length() {
return None
}
// Path exhausted but template remains
if path_idx >= path_parts.length() {
return if segments[seg_idx] is GlobStar {
let trial_params : Map[String, StringView] = {}
params.each((key, value) => trial_params.set(key, value))
trial_params.set("_", "")
match_compiled_segments(
segments,
path_parts,
seg_idx + 1,
path_idx,
trial_params,
)
} else {
None
}
}
let path_part = path_parts[path_idx]
match segments[seg_idx] {
Static(expected) =>
// Compare StringView directly with the stored String to avoid
// allocating a String from the StringView on every segment compare.
if path_part == expected[:] {
match_compiled_segments(
segments,
path_parts,
seg_idx + 1,
path_idx + 1,
params,
)
} else {
None
}
Param(name) => {
params.set(name, path_part)
match_compiled_segments(
segments,
path_parts,
seg_idx + 1,
path_idx + 1,
params,
)
}
Wildcard => {
params.set("_", path_part)
match_compiled_segments(
segments,
path_parts,
seg_idx + 1,
path_idx + 1,
params,
)
}
GlobStar => {
let mut end_idx = path_idx
while end_idx <= path_parts.length() {
let matched_segments : Array[StringView] = []
let mut i = path_idx
while i < end_idx {
matched_segments.push(path_parts[i])
i = i + 1
}
let trial_params : Map[String, StringView] = {}
params.each((key, value) => trial_params.set(key, value))
trial_params.set("_", matched_segments.join("/"))
match
match_compiled_segments(
segments,
path_parts,
seg_idx + 1,
end_idx,
trial_params,
) {
Some(result) => return Some(result)
None => ()
}
end_idx = end_idx + 1
}
None
}
}
}