use crate::path::{Param, Pattern, SegmentAt};
use crate::routes::{Node, RouteStore};
use crate::stack_vec::StackVec;
#[derive(Debug)]
pub struct Found {
pub is_leaf: bool,
pub route: Option<usize>,
pub param: Option<Param>,
pub at: SegmentAt,
}
pub fn visit<T>(
path: &str,
store: &RouteStore<T>,
segments: &StackVec<SegmentAt, 5>,
) -> Vec<Found> {
let mut results = Vec::new();
let root = store.get(0);
let at = SegmentAt::new(0, 0);
match segments.get(0) {
Some(range) => {
results.push(Found::new(root.route, None, at));
visit_node(&mut results, store, root, path, segments, range, 0);
}
None => {
results.push(Found::leaf(root.route, None, at));
visit_index(&mut results, store, root);
}
}
results
}
impl Found {
fn new(route: Option<usize>, param: Option<Param>, at: SegmentAt) -> Self {
Self {
is_leaf: false,
route,
param,
at,
}
}
fn leaf(route: Option<usize>, param: Option<Param>, at: SegmentAt) -> Self {
Self {
is_leaf: true,
route,
param,
at,
}
}
}
fn visit_node<T>(
results: &mut Vec<Found>,
store: &RouteStore<T>,
node: &Node,
path: &str,
segments: &StackVec<SegmentAt, 5>,
range: &SegmentAt,
index: usize,
) {
let segment = match path.get(range.start()..range.end()) {
Some(slice) => slice,
None => {
return;
}
};
for key in node.entries().copied() {
let entry = store.get(key);
match &entry.pattern {
Pattern::Static(param) if segment == param.as_str() => {
let index = index + 1;
let at = range.clone();
match segments.get(index) {
Some(range) => {
results.push(Found::new(entry.route, None, at));
visit_node(results, store, entry, path, segments, range, index);
}
None => {
results.push(Found::leaf(entry.route, None, at));
visit_index(results, store, entry);
}
}
}
Pattern::Dynamic(param) => {
let index = index + 1;
let at = range.clone();
match segments.get(index) {
Some(range) => {
results.push(Found::new(entry.route, Some(param.clone()), at));
visit_node(results, store, entry, path, segments, range, index);
}
None => {
results.push(Found::leaf(entry.route, Some(param.clone()), at));
visit_index(results, store, entry);
}
}
}
Pattern::CatchAll(param) => {
results.push(Found::leaf(
entry.route,
Some(param.clone()),
SegmentAt::new(range.start(), path.len()),
));
}
_ => {}
}
}
}
fn visit_index<T>(
results: &mut Vec<Found>,
store: &RouteStore<T>,
node: &Node,
) {
for key in node.entries().copied() {
let entry = store.get(key);
if let Pattern::CatchAll(param) = &entry.pattern {
results.push(Found::leaf(
entry.route,
Some(param.clone()),
SegmentAt::new(0, 0),
));
}
}
}