use std::cell::RefCell;
use std::collections::BTreeMap;
use std::collections::VecDeque;
use std::error::Error as StdError;
use std::rc::Rc;
#[derive(Debug)]
pub enum RadixTreeError {
AddressNotInTree(String),
}
impl StdError for RadixTreeError {
fn description(&self) -> &str {
match *self {
RadixTreeError::AddressNotInTree(ref msg) => msg,
}
}
}
impl std::fmt::Display for RadixTreeError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match *self {
RadixTreeError::AddressNotInTree(ref s) => write!(f, "AddressNotInTree: {}", s),
}
}
}
#[derive(Debug, Clone, Default)]
pub struct Node<T> {
address: String,
children: BTreeMap<String, Rc<RefCell<Node<T>>>>,
data: Option<T>,
}
#[derive(Default, Debug, Clone)]
pub struct RadixTree<T> {
root: Rc<RefCell<Node<T>>>,
}
impl<T: Clone> RadixTree<T> {
pub fn new() -> Self {
RadixTree {
root: Rc::new(RefCell::new(Node {
address: "".to_string(),
children: BTreeMap::new(),
data: None,
})),
}
}
fn get_child(
node: &Rc<RefCell<Node<T>>>,
address: &str,
) -> Result<Rc<RefCell<Node<T>>>, RadixTreeError> {
node.borrow()
.children
.values()
.find(|child| address.starts_with(&child.borrow().address))
.map(Rc::clone)
.ok_or_else(|| RadixTreeError::AddressNotInTree("Address Not In Tree".to_string()))
}
fn walk_to_address(&self, address: &str) -> Vec<Rc<RefCell<Node<T>>>> {
let mut current_node = Rc::clone(&self.root);
let mut results = vec![Rc::clone(¤t_node)];
while address != current_node.borrow().address.as_str()
&& address.starts_with(current_node.borrow().address.as_str())
{
match RadixTree::get_child(¤t_node, address) {
Ok(child) => {
results.push(Rc::clone(&child));
current_node = child;
}
Err(_) => break,
}
}
results
}
pub fn walk(&self, address: &str) -> Vec<(String, Option<T>)> {
let mut return_nodes = Vec::new();
let accumulated_nodes = self.walk_to_address(address);
for node in accumulated_nodes.iter() {
return_nodes.push((node.borrow().address.clone(), node.borrow().data.clone()));
}
if let Some(node) = accumulated_nodes.iter().last() {
let mut to_process = VecDeque::new();
let descendants = node.borrow().children.clone();
for descendant in descendants.values() {
to_process.push_front(Rc::clone(descendant));
}
while let Some(current_child) = to_process.pop_front() {
return_nodes.push((
current_child.borrow().address.clone(),
current_child.borrow().data.clone(),
));
let additional_descendants = ¤t_child.borrow().children;
for child in additional_descendants.values() {
to_process.push_front(Rc::clone(child));
}
}
}
return_nodes
}
fn get_or_create(&self, address: &str) -> Rc<RefCell<Node<T>>> {
let accumulated_nodes = self.walk_to_address(address);
let first_ancestor = accumulated_nodes
.iter()
.last()
.expect("Node ancestors not formed correctly");
if first_ancestor.borrow().address == address {
return Rc::clone(first_ancestor);
}
let new_node = Rc::new(RefCell::new(Node {
address: address.to_string(),
children: BTreeMap::new(),
data: None,
}));
let prefix_len = first_ancestor.borrow().address.len();
let option_ancestor_child = first_ancestor
.borrow()
.children
.values()
.find(|child| {
let child_address = &child.borrow().address;
let child_address_prefix: String =
child_address.chars().skip(prefix_len).collect::<String>();
let address_prefix: String =
address.chars().skip(prefix_len).take(1).collect::<String>();
child_address_prefix.starts_with(&address_prefix)
})
.map(Rc::clone);
let ancestor_child = match option_ancestor_child {
Some(child) => child,
None => {
first_ancestor
.borrow_mut()
.children
.insert(address.to_string(), Rc::clone(&new_node));
return new_node;
}
};
if ancestor_child.borrow().address.starts_with(address) {
first_ancestor
.borrow_mut()
.children
.insert(address.to_string(), Rc::clone(&new_node));
new_node
.borrow_mut()
.children
.insert(address.to_string(), Rc::clone(&ancestor_child));
first_ancestor
.borrow_mut()
.children
.remove(&ancestor_child.borrow().address);
return new_node;
};
let ancestor_child_address = ancestor_child.borrow().address.clone();
let shorter = if address.len() < ancestor_child_address.len() {
address
} else {
&ancestor_child_address
};
let intermediate_node = Rc::new(RefCell::new(Node {
address: String::from(""),
children: BTreeMap::new(),
data: None,
}));
for i in 0..shorter.len() {
if address.chars().nth(i) != ancestor_child_address.chars().nth(i) {
intermediate_node.borrow_mut().address = shorter[..i].to_string();
break;
}
}
let mut new_children_map = BTreeMap::new();
new_children_map.insert(new_node.borrow().address.clone(), Rc::clone(&new_node));
new_children_map.insert(
ancestor_child.borrow().address.clone(),
Rc::clone(&ancestor_child),
);
intermediate_node
.borrow_mut()
.children
.append(&mut new_children_map);
first_ancestor.borrow_mut().children.insert(
intermediate_node.borrow().address.clone(),
Rc::clone(&intermediate_node),
);
first_ancestor
.borrow_mut()
.children
.remove(&ancestor_child.borrow().address.clone());
new_node
}
pub fn update(&self, address: &str, updater: &dyn Fn(Option<T>) -> Option<T>, prune: bool) {
let node = self.get_or_create(address);
let existing_data = node.borrow_mut().data.take();
node.borrow_mut().data = updater(existing_data);
if prune {
node.borrow_mut().children.clear();
}
}
pub fn prune(&self, address: &str) {
let accumulated_nodes = self.walk_to_address(address);
if let Some(node) = accumulated_nodes.iter().last() {
node.borrow_mut().children.clear()
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn tree_creation() {
let tree: RadixTree<i32> = RadixTree::new();
assert_eq!(tree.root.borrow().children.len(), 0);
assert_eq!(tree.root.borrow().address, "".to_string());
}
#[test]
fn tree_insert_children() {
let tree: RadixTree<i32> = RadixTree::new();
tree.get_or_create("radix");
tree.get_or_create("radish");
tree.get_or_create("radon");
assert_eq!(tree.root.borrow().children.len(), 1);
let found_node_rad = tree.get_or_create("rad");
assert_eq!(found_node_rad.borrow().address, "rad".to_string());
assert_eq!(found_node_rad.borrow().children.len(), 2);
let found_node_radi = tree.get_or_create("radi");
assert_eq!(found_node_radi.borrow().address, "radi".to_string());
assert_eq!(found_node_radi.borrow().children.len(), 2);
let found_node_radix = tree.get_or_create("radix");
assert_eq!(found_node_radix.borrow().address, "radix".to_string());
assert_eq!(found_node_radix.borrow().children.len(), 0);
let found_node_radish = tree.get_or_create("radish");
assert_eq!(found_node_radish.borrow().address, "radish".to_string());
assert_eq!(found_node_radish.borrow().children.len(), 0);
let found_node_radon = tree.get_or_create("radon");
assert_eq!(found_node_radon.borrow().address, "radon".to_string());
assert_eq!(found_node_radon.borrow().children.len(), 0);
}
#[test]
fn tree_walk_to_address() {
let tree: RadixTree<i32> = RadixTree::new();
tree.get_or_create("radix");
tree.get_or_create("radish");
tree.get_or_create("radon");
let walk_to_results_rad = tree.walk_to_address("rad");
assert_eq!(walk_to_results_rad.len(), 2);
let walk_to_results_radon = tree.walk_to_address("radon");
assert_eq!(walk_to_results_radon.len(), 3);
let walk_to_results_radix = tree.walk_to_address("radix");
assert_eq!(walk_to_results_radix.len(), 4);
}
#[test]
fn tree_walk() {
let tree: RadixTree<i32> = RadixTree::new();
tree.get_or_create("radix");
tree.get_or_create("radish");
tree.get_or_create("radon");
let walk_results_radix = tree.walk("radix");
assert_eq!(walk_results_radix.len(), 4);
assert!(walk_results_radix.contains(&("radix".to_string(), None)));
let walk_results_rad = tree.walk("rad");
assert_eq!(walk_results_rad.len(), 6);
assert!(walk_results_rad.contains(&("rad".to_string(), None)));
}
fn update_data(data: Option<i32>) -> Option<i32> {
if data.is_none() {
return Some(1);
} else {
return Some(data.unwrap() + 1);
}
}
#[test]
fn tree_node_update() {
let tree: RadixTree<i32> = RadixTree::new();
tree.get_or_create("radix");
tree.get_or_create("radish");
tree.get_or_create("radon");
tree.update("radix", &update_data, false);
let updated_node = tree.get_or_create("radix");
assert_eq!(updated_node.borrow().data, Some(1));
tree.update("radix", &update_data, false);
assert_eq!(updated_node.borrow().data, Some(2));
}
#[test]
fn tree_prune() {
let tree: RadixTree<i32> = RadixTree::new();
tree.get_or_create("radix");
tree.get_or_create("radish");
tree.get_or_create("radon");
tree.prune("rad");
let parent_node = tree.get_or_create("rad");
let mut parent_node_walk = tree.walk("rad");
assert_eq!(parent_node.borrow().children.len(), 0);
assert!(!parent_node_walk.contains(&("radi".to_string(), None)));
assert!(parent_node_walk.contains(&("rad".to_string(), None)));
tree.get_or_create("radish");
tree.get_or_create("radix");
parent_node_walk = tree.walk("rad");
assert_eq!(parent_node.borrow().children.len(), 1);
assert!(parent_node_walk.contains(&("radix".to_string(), None)));
assert!(parent_node_walk.contains(&("radish".to_string(), None)));
}
}