use std::collections::HashMap;
use crate::{
error::{TrieInsert, TrieReplace},
key_repr::Key,
};
pub mod display;
pub mod iterator;
#[cfg(test)]
mod tests;
#[derive(Debug)]
pub struct Trie<K, V>
where
K: Clone + Eq + std::hash::Hash + std::fmt::Debug,
V: Clone + PartialEq + std::fmt::Debug,
{
root: Node<K, V>,
}
pub type MapTrie<V> = Trie<Key, V>;
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum NodeValue<K, V>
where
K: Clone + Eq + std::hash::Hash + std::fmt::Debug,
V: Clone + PartialEq + std::fmt::Debug,
{
Parent { children: HashMap<K, Node<K, V>> },
Child { value: V },
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Node<K, V>
where
K: Clone + Eq + std::hash::Hash + std::fmt::Debug,
V: Clone + PartialEq + std::fmt::Debug,
{
value: NodeValue<K, V>,
}
impl<K, V> Default for Trie<K, V>
where
K: Clone + Eq + std::hash::Hash + std::fmt::Debug,
V: Clone + PartialEq + std::fmt::Debug,
{
fn default() -> Self {
Self::new()
}
}
impl<K, V> Trie<K, V>
where
K: Clone + Eq + std::hash::Hash + std::fmt::Debug,
V: Clone + PartialEq + std::fmt::Debug,
{
#[must_use]
pub fn new() -> Self {
Self {
root: Node::new_parent(),
}
}
pub fn root_node(&self) -> &Node<K, V> {
&self.root
}
pub fn get(&self, key: &[K]) -> Option<&Node<K, V>> {
self.root.get(key)
}
pub fn get_mut(&mut self, key: &[K]) -> Option<&mut Node<K, V>> {
self.root.get_mut(key)
}
#[allow(clippy::missing_panics_doc)]
pub fn try_get(&self, key: &[K]) -> (&Node<K, V>, Vec<K>) {
self.root.try_get(key)
}
pub fn insert(&mut self, key: &[K], value: V) -> Result<(), TrieInsert<K, V>> {
self.root.insert(key, value)
}
pub fn replace_node(
&mut self,
key: &[K],
node: Node<K, V>,
) -> Result<Node<K, V>, TrieReplace<K>> {
self.root.replace_node(key, node)
}
#[allow(clippy::missing_panics_doc)]
pub fn insert_node(&mut self, key: &[K], node: &Node<K, V>) -> Result<(), TrieInsert<K, V>> {
self.root.insert_node(key, node)
}
}
impl<K, V> Node<K, V>
where
K: Clone + Eq + std::hash::Hash + std::fmt::Debug,
V: Clone + PartialEq + std::fmt::Debug,
{
pub fn get(&self, key: &[K]) -> Option<&Node<K, V>> {
let mut current_node = self;
for ch in key {
if let NodeValue::Parent { children } = ¤t_node.value {
current_node = children.get(ch)?;
} else {
return None;
}
}
Some(current_node)
}
pub fn get_mut(&mut self, key: &[K]) -> Option<&mut Node<K, V>> {
let mut current_node = self;
for ch in key {
if let NodeValue::Parent { children } = &mut current_node.value {
current_node = children.get_mut(ch)?;
} else {
return None;
}
}
Some(current_node)
}
#[allow(clippy::missing_panics_doc)]
pub fn try_get(&self, key: &[K]) -> (&Node<K, V>, Vec<K>) {
let mut current_node = self;
let mut current_key = vec![];
for ch in key {
if let NodeValue::Parent { children } = ¤t_node.value {
current_node = if let Some(node) = children.get(ch) {
let (key, _) = children.get_key_value(ch).expect("This exists, we checked");
current_key.push(key.clone());
node
} else {
return (current_node, current_key);
};
} else {
return (current_node, current_key);
}
}
(current_node, current_key)
}
pub fn insert(&mut self, key: &[K], value: V) -> Result<(), TrieInsert<K, V>> {
self.insert_node(key, &Node::new_child(value))
}
pub fn replace_node(
&mut self,
key: &[K],
node: Node<K, V>,
) -> Result<Node<K, V>, TrieReplace<K>> {
if let Some(old_node) = self.get_mut(key) {
Ok(std::mem::replace(old_node, node))
} else {
Err(TrieReplace::NoNodeWithKey(key.to_vec()))
}
}
#[allow(clippy::missing_panics_doc)]
pub fn insert_node(&mut self, key: &[K], node: &Node<K, V>) -> Result<(), TrieInsert<K, V>> {
let (_, found_key) = self.try_get(key).clone();
if found_key == key {
return Err(TrieInsert::KeyAlreadySet(found_key.clone()));
}
let needed_nodes_key = key
.strip_prefix(&found_key[..])
.expect("The node's location is a prefix");
let needed_nodes_length = needed_nodes_key.len();
let mut current_node = self
.get_mut(&found_key[..])
.expect("This should always exists");
let mut current_location = found_key.clone();
let mut counter = 1;
for ch in needed_nodes_key {
current_location.push(ch.to_owned());
let next_node = if counter == needed_nodes_length {
node.clone()
} else {
Node::new_parent()
};
current_node = match &mut current_node.value {
NodeValue::Parent { children } => {
assert_eq!(children.get(ch), None);
children.insert(ch.to_owned(), next_node);
children.get_mut(ch).expect("Was just inserted")
}
NodeValue::Child { value } => {
return Err(TrieInsert::KeyIncludesChild {
child_key: key.to_vec(),
child_value: value.to_owned(),
});
}
};
counter += 1;
}
Ok(())
}
}
impl<K, V> Node<K, V>
where
K: Clone + Eq + std::hash::Hash + std::fmt::Debug,
V: Clone + PartialEq + std::fmt::Debug,
{
#[must_use]
pub fn new_child(value: V) -> Self {
Self {
value: NodeValue::Child { value },
}
}
#[must_use]
pub fn new_parent() -> Self {
Self {
value: NodeValue::Parent {
children: HashMap::new(),
},
}
}
pub fn value(&self) -> Option<&V> {
match &self.value {
NodeValue::Parent { children: _ } => None,
NodeValue::Child { value } => Some(value),
}
}
pub fn children(&self) -> Option<&HashMap<K, Self>> {
match &self.value {
NodeValue::Parent { children } => Some(children),
NodeValue::Child { value: _ } => None,
}
}
}