use super::route_node_merge::*;
use super::*;
use crate::template::template_pairs::parse_template_pairs;
use regex::Regex;
use std::borrow::Cow;
use std::cmp::min;
pub fn route_node_parse<'r, 'f, K: Copy>(
node_rc: RouteNodeRc<'r, K>,
path: &'f str,
maximum_parameter_value_length: usize,
) -> (Option<K>, Vec<&'r str>, Vec<&'f str>) {
let mut path = path;
let mut parameter_values: Vec<&str> = Default::default();
let node = node_rc.borrow();
if node.has_parameter {
if path.is_empty() {
return Default::default();
}
let index = if node.anchor.is_empty() {
Some(path.len())
} else {
path[..min(
maximum_parameter_value_length + node.anchor.len(),
path.len(),
)]
.find(node.anchor)
};
if let Some(index) = index {
let value = &path[..index];
path = &path[index + node.anchor.len()..];
parameter_values.push(value);
} else {
return Default::default();
}
} else {
if !path.starts_with(node.anchor) {
return Default::default();
}
path = &path[node.anchor.len()..];
}
for child_rc in &node.children {
if let (Some(child_route_name), child_route_parameter_names, mut child_parameters_values) =
route_node_parse(child_rc.clone(), path, maximum_parameter_value_length)
{
let mut parameter_values = parameter_values.clone();
parameter_values.append(&mut child_parameters_values);
return (
Some(child_route_name),
child_route_parameter_names,
parameter_values,
);
}
}
if path.is_empty() {
if let Some(route_key) = node.route_key {
return (
Some(route_key),
node.route_parameter_names.clone(),
parameter_values,
);
}
}
Default::default()
}
pub fn route_node_stringify<'r, 'f, K>(
node_rc: RouteNodeRc<'r, K>,
parameter_values: Vec<Cow<'f, str>>,
) -> Cow<'f, str>
where
'r: 'f,
{
let mut parameter_values = parameter_values.clone();
let mut current_node_rc = Some(node_rc);
let mut path_parts = Vec::new();
while let Some(node_rc) = current_node_rc {
let node = node_rc.borrow();
path_parts.insert(0, Cow::Borrowed(node.anchor));
if node.has_parameter {
let value = parameter_values.pop().unwrap();
path_parts.insert(0, value);
}
current_node_rc = node
.parent
.as_ref()
.map(|parent_node_weak| parent_node_weak.upgrade().unwrap());
}
path_parts
.into_iter()
.reduce(|path, path_part| path + path_part)
.unwrap()
}
pub fn route_node_insert<'r, K: Copy>(
root_node_rc: RouteNodeRc<'r, K>,
route_key: K,
template: &'r str,
parameter_placeholder_re: &'r Regex,
) -> RouteNodeRc<'r, K> {
let template_pairs: Vec<_> = parse_template_pairs(template, parameter_placeholder_re).collect();
let route_parameter_names: Vec<_> = template_pairs
.iter()
.cloned()
.filter_map(|(_anchor, parameter)| parameter)
.collect();
let mut node_current_rc = root_node_rc.clone();
for index in 0..template_pairs.len() {
let (anchor, parameter) = template_pairs[index];
let has_parameter = parameter.is_some();
let route_key = if index == template_pairs.len() - 1 {
Some(route_key)
} else {
None
};
let (common_prefix_length, child_node_rc) =
route_node_find_similar_child(&node_current_rc.borrow(), anchor, has_parameter);
node_current_rc = route_node_merge(
node_current_rc,
child_node_rc,
anchor,
has_parameter,
route_key,
route_parameter_names.clone(),
common_prefix_length,
);
}
node_current_rc
}
#[cfg(test)]
mod tests {
use super::*;
use crate::template::TEMPLATE_PLACEHOLDER_REGEX;
use itertools::Itertools;
#[test]
fn route_node_permutations() {
let route_configs = ["/a", "/b/{x}", "/b/{x}/", "/b/{x}/c", "/b/{y}/d"];
let mut node_root_previous_rc = None;
for route_configs in route_configs.iter().permutations(route_configs.len()) {
let node_root_rc = Rc::new(RefCell::new(RouteNode::default()));
for template in route_configs {
route_node_insert(
node_root_rc.clone(),
template,
template,
&TEMPLATE_PLACEHOLDER_REGEX,
);
}
{
let node_root = node_root_rc.borrow();
assert_eq!(node_root.children.len(), 1);
}
if let Some(node_root_previous) = node_root_previous_rc {
assert_eq!(node_root_rc, node_root_previous);
}
node_root_previous_rc = Some(node_root_rc.clone());
}
}
}