use alloc::vec;
use alloc::vec::Vec;
use crate::compiler::Compiler;
use crate::errors::InsertError;
use crate::node::Data;
use crate::parser::{Part, Template};
use crate::router::Router;
use crate::state::{DynamicState, EndWildcardState, RootState, StaticState, WildcardState};
#[derive(Clone)]
pub struct RouterBuilder<T> {
root: BuilderNode<RootState, T>,
}
impl<T> RouterBuilder<T> {
#[must_use]
pub const fn new() -> Self {
Self {
root: BuilderNode::new(RootState::new()),
}
}
pub fn insert(&mut self, template: &str, data: T) -> Result<(), InsertError> {
let mut parsed = Template::new(template)?;
if let Some(found) = self.root.conflict(&parsed.parts) {
return Err(InsertError::Conflict {
existing: found.template.clone().into(),
});
}
self.root.insert(
&mut parsed,
Data {
data,
template: template.into(),
},
);
Ok(())
}
#[must_use]
pub fn build(self) -> Router<T> {
Compiler::run(self.root)
}
}
#[derive(Clone, Debug)]
pub(crate) struct BuilderNode<S, T> {
pub state: S,
pub data: Option<Data<T>>,
pub static_children: Vec<BuilderNode<StaticState, T>>,
pub dynamic_children: Vec<BuilderNode<DynamicState, T>>,
pub wildcard_children: Vec<BuilderNode<WildcardState, T>>,
pub end_wildcard: Option<EndWildcardState<T>>,
}
impl<S, T> BuilderNode<S, T> {
pub(crate) const fn new(state: S) -> Self {
Self {
state,
data: None,
static_children: Vec::new(),
dynamic_children: Vec::new(),
wildcard_children: Vec::new(),
end_wildcard: None,
}
}
pub(crate) fn insert(&mut self, template: &mut Template<'_>, data: Data<T>) {
if let Some(part) = template.parts.pop() {
match part {
Part::Static { prefix } => self.insert_static(template, data, prefix),
Part::Dynamic { name } => self.insert_dynamic(template, data, name),
Part::Wildcard { name } if template.parts.is_empty() => {
self.insert_end_wildcard(data, name);
}
Part::Wildcard { name } => self.insert_wildcard(template, data, name),
}
} else {
self.data = Some(data);
}
}
fn insert_static(&mut self, template: &mut Template<'_>, data: Data<T>, prefix: &[u8]) {
if let Some(child) = self
.static_children
.iter_mut()
.find(|child| child.state.prefix[0] == prefix[0])
{
let common_prefix = prefix
.iter()
.zip(&child.state.prefix)
.take_while(|&(a, b)| a == b)
.count();
if common_prefix >= child.state.prefix.len() {
if common_prefix >= prefix.len() {
child.insert(template, data);
} else {
child.insert_static(template, data, &prefix[common_prefix..]);
}
return;
}
let new_child_a = BuilderNode {
state: StaticState::new(&child.state.prefix[common_prefix..]),
data: child.data.take(),
static_children: core::mem::take(&mut child.static_children),
dynamic_children: core::mem::take(&mut child.dynamic_children),
wildcard_children: core::mem::take(&mut child.wildcard_children),
end_wildcard: core::mem::take(&mut child.end_wildcard),
};
let new_child_b = BuilderNode::new(StaticState::new(&prefix[common_prefix..]));
child.state = StaticState::new(&child.state.prefix[..common_prefix]);
if prefix[common_prefix..].is_empty() {
child.static_children = vec![new_child_a];
child.insert(template, data);
} else {
child.static_children = vec![new_child_a, new_child_b];
child.static_children[1].insert(template, data);
}
return;
}
let mut child = BuilderNode::new(StaticState::new(prefix));
child.insert(template, data);
self.static_children.push(child);
}
fn insert_dynamic(&mut self, template: &mut Template<'_>, data: Data<T>, name: &str) {
if let Some(child) = self
.dynamic_children
.iter_mut()
.find(|child| *child.state.name == *name)
{
child.insert(template, data);
} else {
let mut child = BuilderNode::new(DynamicState::new(name));
child.insert(template, data);
self.dynamic_children.push(child);
}
}
fn insert_wildcard(&mut self, template: &mut Template<'_>, data: Data<T>, name: &str) {
if let Some(child) = self
.wildcard_children
.iter_mut()
.find(|child| *child.state.name == *name)
{
child.insert(template, data);
} else {
let mut child = BuilderNode::new(WildcardState::new(name));
child.insert(template, data);
self.wildcard_children.push(child);
}
}
fn insert_end_wildcard(&mut self, data: Data<T>, name: &str) {
self.end_wildcard = Some(EndWildcardState::new(name, data));
}
pub(crate) fn conflict(&self, parts: &[Part<'_>]) -> Option<&Data<T>> {
let Some((part, remaining)) = parts.split_last() else {
return self.data.as_ref();
};
match part {
Part::Static { prefix } => self.conflict_static(remaining, prefix),
Part::Dynamic { .. } => self.conflict_dynamic(remaining),
Part::Wildcard { .. } if remaining.is_empty() => self.conflict_end_wildcard(),
Part::Wildcard { .. } => self.conflict_wildcard(remaining),
}
}
fn conflict_static(&self, parts: &[Part<'_>], prefix: &[u8]) -> Option<&Data<T>> {
for child in &self.static_children {
if prefix.len() >= child.state.prefix.len()
&& child.state.prefix.iter().zip(prefix).all(|(a, b)| a == b)
{
let remaining_prefix = &prefix[child.state.prefix.len()..];
if remaining_prefix.is_empty() {
if let Some(data) = child.conflict(parts) {
return Some(data);
}
} else if let Some(data) = child.conflict_static(parts, remaining_prefix) {
return Some(data);
}
}
}
None
}
fn conflict_dynamic(&self, parts: &[Part<'_>]) -> Option<&Data<T>> {
for child in &self.dynamic_children {
if let Some(data) = child.conflict(parts) {
return Some(data);
}
}
None
}
fn conflict_wildcard(&self, parts: &[Part<'_>]) -> Option<&Data<T>> {
for child in &self.wildcard_children {
if let Some(data) = child.conflict(parts) {
return Some(data);
}
}
None
}
fn conflict_end_wildcard(&self) -> Option<&Data<T>> {
let child = self.end_wildcard.as_ref()?;
Some(&child.data)
}
}