use crate::collections::HashMap;
use crate::compile::{Component, ComponentRef, IntoComponent};
use std::mem;
#[derive(Default, Debug, Clone)]
pub struct Names {
root: Node,
}
impl Names {
pub(crate) fn insert<I>(&mut self, iter: I) -> bool
where
I: IntoIterator,
I::Item: IntoComponent,
{
let mut current = &mut self.root;
for c in iter {
current = current.children.entry(c.into_component()).or_default();
}
mem::replace(&mut current.term, true)
}
pub(crate) fn contains<I>(&self, iter: I) -> bool
where
I: IntoIterator,
I::Item: IntoComponent,
{
self.find_node(iter).map(|n| n.term).unwrap_or_default()
}
pub(crate) fn contains_prefix<I>(&self, iter: I) -> bool
where
I: IntoIterator,
I::Item: IntoComponent,
{
self.find_node(iter).is_some()
}
pub(crate) fn iter_components<'a, I: 'a>(
&'a self,
iter: I,
) -> impl Iterator<Item = ComponentRef<'a>> + 'a
where
I: IntoIterator,
I::Item: IntoComponent,
{
let mut current = &self.root;
for c in iter {
let c = c.into_component();
current = match current.children.get(&c) {
Some(node) => node,
None => return IterComponents(None),
};
}
return IterComponents(Some(current.children.keys()));
struct IterComponents<I>(Option<I>);
impl<'a, I> Iterator for IterComponents<I>
where
I: Iterator<Item = &'a Component>,
{
type Item = ComponentRef<'a>;
fn next(&mut self) -> Option<Self::Item> {
let mut iter = self.0.take()?;
let next = iter.next()?;
self.0 = Some(iter);
Some(next.as_component_ref())
}
}
}
fn find_node<I>(&self, iter: I) -> Option<&Node>
where
I: IntoIterator,
I::Item: IntoComponent,
{
let mut current = &self.root;
for c in iter {
let c = c.as_component_ref().into_component();
current = current.children.get(&c)?;
}
Some(current)
}
}
#[derive(Default, Debug, Clone)]
struct Node {
term: bool,
children: HashMap<Component, Node>,
}
#[cfg(test)]
mod tests {
use super::Names;
#[test]
fn insert() {
let mut names = Names::default();
assert!(!names.contains(&["test"]));
assert!(!names.insert(&["test"]));
assert!(names.contains(&["test"]));
assert!(names.insert(&["test"]));
}
#[test]
fn contains() {
let mut names = Names::default();
assert!(!names.contains(&["test"]));
assert!(!names.insert(&["test"]));
assert!(names.contains(&["test"]));
assert!(names.insert(&["test"]));
}
}