use std::ptr;
use std::string::String;
use std::vec::Vec;
mod tra;
use tra::{tsdv, TraStrain};
mod uc;
use uc::UC;
pub type Branches = Vec<Box<Node>>;
pub type LeftBranches = Vec<Box<Node>>;
pub type RightBranches = Vec<Box<Node>>;
type NodeTrace = Vec<PathNode>;
type EntryTrace = Vec<char>;
#[derive(Clone, PartialEq, Debug)]
struct PathNode(usize, *mut Node);
impl PathNode {
fn n_mut<'a>(&self) -> &'a mut Node {
Node::as_mut(self.1)
}
}
pub type Entry<'a> = KeyEntry<'a>;
pub type Key<'a> = KeyEntry<'a>;
#[derive(Clone)]
pub struct Node {
pub c: char,
pub supernode: *const Node,
pub branches: Option<Branches>,
pub lrref: *const Node,
#[cfg(test)]
id: usize,
}
const NULL_CHAR: char = '\0';
const NULL_NODE: *const Node = ptr::null();
impl Node {
fn lrref(&self) -> bool {
self.lrref != NULL_NODE
}
const fn branches(&self) -> bool {
self.branches.is_some()
}
const fn empty() -> Self {
Node {
c: NULL_CHAR,
supernode: NULL_NODE,
branches: None,
lrref: NULL_NODE,
#[cfg(test)]
id: 0,
}
}
const fn new(c: char, supernode: *const Node) -> Self {
Node {
c,
supernode,
branches: None,
lrref: NULL_NODE,
#[cfg(test)]
id: 0,
}
}
fn empty_boxed() -> Box<Self> {
Box::new(Self::empty())
}
fn new_boxed(c: char, supernode: *const Node) -> Box<Self> {
Box::new(Self::new(c, supernode))
}
fn as_mut<'a>(n: *mut Self) -> &'a mut Self {
unsafe { n.as_mut().unwrap_unchecked() }
}
fn as_ref<'a>(n: *const Self) -> &'a Self {
unsafe { n.as_ref().unwrap_unchecked() }
}
const fn to_mut_ptr(&self) -> *mut Self {
(self as *const Self).cast_mut()
}
}
pub struct KeyEntry<'a>(&'a str);
impl<'a> KeyEntry<'a> {
pub const fn new(key: &'a str) -> Option<Self> {
if key.len() == 0 {
None
} else {
Some(Self(key))
}
}
}
impl<'a> std::ops::Deref for KeyEntry<'a> {
type Target = str;
fn deref(&self) -> &str {
self.0
}
}
#[cfg_attr(test, derive(Clone, Debug, PartialEq))]
pub enum LeftRight {
Left = 0,
Right = 1,
}
fn insert_crux<'a>(mut supernode: &'a mut Node, e: &Entry) -> &'a mut Node {
let e = e.0;
let mut swap = Node::empty_boxed();
let mut sn_ptr: *const Node = supernode;
for c in e.chars() {
let branches = supernode.branches.get_or_insert_with(|| Branches::new());
let ix = if let Some(i) = index_of_c(branches, c) {
i
} else {
let boxed = Node::new_boxed(c, sn_ptr);
branches.push(boxed);
branches.len() - 1
};
let node = &mut branches[ix];
std::mem::swap(&mut swap, node);
let n_raw = Box::into_raw(swap);
swap = unsafe { Box::from_raw(n_raw) };
std::mem::swap(&mut swap, node);
supernode = node;
sn_ptr = n_raw;
}
supernode
}
fn index_of_c(branches: &Branches, c: char) -> Option<usize> {
let branches_len = branches.len();
let mut ix = 0;
while ix < branches_len {
let n = &branches[ix];
if n.c == c {
return Some(ix);
}
ix += 1;
}
None
}
const fn cl_lrref(keyentry_n: &mut Node) -> bool {
if keyentry_n.branches() {
keyentry_n.lrref = NULL_NODE;
true
} else {
false
}
}
fn delete_subnode(n: &mut Node, subnode_ix: usize) -> bool {
let n_branches = n.branches.as_mut().unwrap();
_ = n_branches.swap_remove(subnode_ix);
if n_branches.len() == 0 {
n.branches = None;
} else {
return true;
}
if n.lrref() {
return true;
}
return false;
}
fn delete_key_side<'a>(path: &NodeTrace) {
let mut path = path.iter();
let epn = path.next_back();
let epn = unsafe { epn.unwrap_unchecked() };
let n = epn.n_mut();
if cl_lrref(n) {
return;
}
let mut sub_n_ix = epn.0;
while let Some(PathNode(n_ix, n)) = path.next_back() {
if delete_subnode(Node::as_mut(*n), sub_n_ix) {
break;
}
sub_n_ix = *n_ix;
}
}
fn delete_entry_side(key_side_entry_n: &Node) {
let lrref = key_side_entry_n.lrref.cast_mut();
let node = Node::as_mut(lrref);
if cl_lrref(node) {
return;
}
const NULL_MUT: *mut Node = ptr::null_mut();
let mut node: &mut Node = node;
loop {
let super_n = node.supernode.cast_mut();
if super_n == NULL_MUT {
break;
}
let super_n = Node::as_mut(super_n);
let sn_branches = unsafe { super_n.branches.as_ref().unwrap_unchecked() };
let n_ix = unsafe { index_of_c(sn_branches, node.c).unwrap_unchecked() };
if delete_subnode(super_n, n_ix) {
break;
}
node = super_n;
}
}
fn set_cap<T>(buf: &mut UC<Vec<T>>, approx_cap: usize) -> usize {
let cp = buf.capacity();
if cp < approx_cap {
buf.reserve(approx_cap);
} else if cp > approx_cap {
*buf.uplift() = Vec::with_capacity(approx_cap);
}
buf.capacity()
}
fn ext(b: &Branches, k_buf: &mut String, e_buf: &mut Vec<char>, o: &mut Vec<(String, String)>) {
for n in b {
k_buf.push(n.c);
let lrref = n.lrref;
if lrref != NULL_NODE {
let k = k_buf.clone();
let e = construct_e(lrref, e_buf);
o.push((k, e));
}
if let Some(b) = n.branches.as_ref() {
ext(b, k_buf, e_buf, o);
}
_ = k_buf.pop();
}
}
fn construct_e(mut node: *const Node, e_buf: &mut Vec<char>) -> String {
loop {
let n = Node::as_ref(node);
let super_n = n.supernode;
if super_n == NULL_NODE {
break;
}
e_buf.push(n.c);
node = super_n;
}
let ret = e_buf.iter().rev().collect::<String>();
e_buf.clear();
ret
}
#[derive(Clone, PartialEq, Debug)]
pub enum Buffer {
Delete = 0,
Member = 1,
}
#[cfg_attr(test, derive(PartialEq, Debug))]
pub struct LrTrie {
left: Node,
right: Node,
trace: UC<NodeTrace>,
entry: UC<EntryTrace>,
count: usize,
}
#[cfg_attr(test, derive(PartialEq, Debug))]
enum TraRes<'a> {
Ok,
OkRef(&'a Node),
UnknownForNotEntry,
UnknownForAbsentPathBranches,
UnknownForAbsentPathNode,
}
const KEY_BUFF_CAP: usize = 1000;
impl LrTrie {
pub const fn new() -> Self {
LrTrie {
left: Node::empty(),
right: Node::empty(),
trace: UC::new(Vec::new()),
entry: UC::new(Vec::new()),
count: 0,
}
}
pub fn insert(&mut self, l_entry: &Entry, r_entry: &Entry) {
let mut cntr = 0;
if self.delete_crux(l_entry, LeftRight::Left, false).is_ok() {
cntr += 1;
}
if self.delete_crux(r_entry, LeftRight::Right, false).is_ok() {
cntr += 1;
}
let l_en = insert_crux(&mut self.left, l_entry);
let r_en = insert_crux(&mut self.right, r_entry);
l_en.lrref = r_en as *const Node;
r_en.lrref = l_en as *const Node;
let count = self.count;
self.count = match cntr {
0 => count + 1,
1 => return,
2 => count - 1,
_ => panic!("Impossible value."),
}
}
fn track(&self, key: &Key, lr: LeftRight, ts: TraStrain) -> TraRes {
let root = self.root(lr);
let trace = self.trace.uplift();
let tracing = TraStrain::has(ts.clone(), tsdv::TRA);
if tracing {
trace.push(PathNode(usize::MAX, root.to_mut_ptr()));
}
let mut key = key.chars();
let mut node = Node::as_ref(root);
while let Some(c) = key.next() {
if let Some(b) = &node.branches {
if let Some(ix) = index_of_c(b, c) {
node = &b[ix];
if tracing {
trace.push(PathNode(ix, node.to_mut_ptr()));
}
continue;
}
return TraRes::UnknownForAbsentPathNode;
}
return TraRes::UnknownForAbsentPathBranches;
}
if node.lrref() {
match ts {
x if TraStrain::has(x.clone(), tsdv::REF) => TraRes::OkRef(node),
x if TraStrain::has(x.clone(), tsdv::EMP) => TraRes::Ok,
_ => panic!("Unsupported result scenario."),
}
} else {
TraRes::UnknownForNotEntry
}
}
pub fn member(&self, key: &Key, lr: LeftRight) -> Option<String> {
let res = self.track(key, lr, TraStrain::NonRef);
if let TraRes::OkRef(en) = res {
let entry = self.entry.uplift();
let ret = construct_e(en.lrref, entry);
Some(ret)
} else {
None
}
}
const fn root(&self, lr: LeftRight) -> &Node {
match lr {
LeftRight::Left => &self.left,
LeftRight::Right => &self.right,
}
}
const fn branches(&self, lr: LeftRight) -> Option<&Branches> {
self.root(lr).branches.as_ref()
}
pub fn delete(&mut self, key: &Key, lr: LeftRight) -> Result<(), ()> {
let res = self.delete_crux(key, lr, true);
self.trace.clear();
if res.is_ok() {
self.count -= 1;
}
res
}
fn delete_crux(&mut self, key: &Key, lr: LeftRight, delete_ks: bool) -> Result<(), ()> {
let ts = if delete_ks {
TraStrain::TraRef
} else {
TraStrain::NonRef
};
if let TraRes::OkRef(en) = self.track(key, lr, ts) {
delete_entry_side(en);
if delete_ks {
delete_key_side(&*self.trace)
}
Ok(())
} else {
Err(())
}
}
pub fn put_buf_cap(&mut self, approx_cap: usize, buf: Buffer) -> usize {
if buf == Buffer::Delete {
set_cap(&mut self.trace, approx_cap)
} else {
#[cfg(test)]
assert_eq!(Buffer::Member, buf);
set_cap(&mut self.entry, approx_cap)
}
}
pub fn aq_buf_cap(&self, buf: Buffer) -> usize {
if buf == Buffer::Delete {
self.trace.capacity()
} else {
#[cfg(test)]
assert_eq!(Buffer::Member, buf);
self.entry.capacity()
}
}
pub fn clear(&mut self) -> usize {
self.left = Node::empty();
self.right = Node::empty();
let count = self.count;
self.count = 0;
count
}
pub const fn count(&self) -> usize {
self.count
}
pub fn extract(&self, lr: LeftRight) -> Option<Vec<(String, String)>> {
let c = self.count;
if c == 0 {
None
} else {
let b = self.branches(lr);
#[cfg(test)]
assert_eq!(true, b.is_some());
let b = unsafe { b.unwrap_unchecked() };
let mut o = Vec::with_capacity(c);
let mut e_buf = Vec::with_capacity(KEY_BUFF_CAP);
let mut k_buf = String::with_capacity(KEY_BUFF_CAP);
ext(b, &mut k_buf, &mut e_buf, &mut o);
Some(o)
}
}
pub fn as_ref(&self) -> Option<(&LeftBranches, &RightBranches)> {
return if let Some(b) = self.left.branches.as_ref() {
let r = unsafe { self.right.branches.as_ref().unwrap_unchecked() };
Some((b, r))
} else {
None
};
}
pub fn as_mut(&mut self) -> Option<(&mut LeftBranches, &mut RightBranches)> {
return if let Some(b) = self.left.branches.as_mut() {
let r = unsafe { self.right.branches.as_mut().unwrap_unchecked() };
Some((b, r))
} else {
None
};
}
}
use std::fmt::{Debug, Formatter};
impl Debug for Node {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
let branches = if self.branches() { "Some" } else { "None" };
let lrref = if self.lrref() { "Some" } else { "None" };
let sn = if self.supernode.is_null() {
"Null"
} else {
"Parent"
};
f.write_fmt(format_args!(
"Node {{\n c: {}\n sn: {}\n branches: {}\n lrref: {}\n}}",
self.c, sn, branches, lrref
))
}
}
impl PartialEq for Node {
fn eq(&self, other: &Self) -> bool {
self.c == other.c
&& self.supernode == other.supernode
&& self.branches == other.branches
&& self.lrref == other.lrref
}
}
#[cfg(test)]
mod aide;
#[cfg(test)]
mod tests_of_units {
use crate::{LeftRight, LrTrie, Node};
use crate::NodeTrace;
impl LrTrie {
fn cc_trace(&mut self) -> NodeTrace {
let trace = &mut self.trace;
let clone = trace.clone();
trace.clear();
clone
}
}
mod lrtrie_test_impl {
use std::ptr::NonNull;
use crate::{LrTrie, Node, PathNode};
#[test]
fn cc_trace() {
let n1 = NonNull::<Node>::dangling().as_ptr();
let n2 = NonNull::<Node>::dangling().as_ptr();
let mut trie = LrTrie::new();
let trace = &mut trie.trace;
trace.push(PathNode(usize::MIN, n1));
trace.push(PathNode(usize::MAX, n2));
let proof = trace.clone();
let test = trie.cc_trace();
assert_eq!(proof, test);
assert_eq!(0, trie.trace.len());
}
}
impl LeftRight {
fn invert(&self) -> Self {
match self {
LeftRight::Left => LeftRight::Right,
LeftRight::Right => LeftRight::Left,
}
}
}
mod leftright_test_impl {
use crate::LeftRight;
#[test]
fn invert() {
assert_eq!(LeftRight::Left, LeftRight::Right.invert());
assert_eq!(LeftRight::Right, LeftRight::Left.invert());
}
}
use crate::PathNode;
impl PathNode {
fn n_ref<'a>(&self) -> &'a Node {
Node::as_ref(self.1)
}
}
mod pathnode_test_impl {
use crate::aide::address;
use crate::{Node, PathNode};
#[test]
fn n_ref() {
let mut n = Node::empty();
let pn = PathNode(0, &mut n);
assert_eq!(address(&n), address(pn.n_ref()));
}
}
mod pathnode {
use crate::aide::address;
use crate::{Node, PathNode};
#[test]
fn n_mut() {
let n = &mut Node::empty();
let pn = PathNode(0, n);
assert_eq!(address(n), address(pn.n_mut()));
}
}
mod node {
use crate::aide::address;
use crate::{Branches, Node, NULL_CHAR};
use std::ptr;
#[test]
fn lrref() {
let mut node = Node::empty();
assert_eq!(false, node.lrref());
node.lrref = &node;
assert!(node.lrref());
}
#[test]
fn branches() {
let mut node = Node::empty();
assert_eq!(false, node.branches());
node.branches = Some(Branches::new());
assert!(node.branches());
}
#[test]
fn empty() {
let null_ptr = ptr::null();
let node = Node::empty();
assert_eq!(NULL_CHAR, node.c);
assert_eq!(null_ptr, node.supernode);
assert_eq!(None, node.branches);
assert_eq!(null_ptr, node.lrref);
}
#[test]
fn new() {
let c = '🫀';
let sn = Node::empty();
let new = Node::new(c, &sn);
assert_eq!(c, new.c);
assert_eq!(address(&sn), new.supernode as usize);
assert_eq!(None, new.branches);
assert_eq!(0, new.lrref as usize);
}
#[test]
fn as_mut() {
let n = &mut Node::empty();
assert_eq!(address(n), address(Node::as_mut(n)));
}
#[test]
fn as_ref() {
let n = &Node::empty();
assert_eq!(address(n), address(Node::as_ref(n)));
}
#[test]
fn to_mut_ptr() {
let n = Node::empty();
let n_add = &n;
assert_eq!(address(n_add), n.to_mut_ptr() as usize);
}
#[test]
fn eq() {
let sn = Node::empty();
let mut n1 = Node::new('x', &sn);
let branches = vec![Node::new_boxed('y', &sn)];
n1.branches = Some(branches);
n1.lrref = &sn;
let n2 = n1.clone();
assert_eq!(true, n1.eq(&n2));
}
}
mod keyentry {
use crate::KeyEntry;
mod new {
use crate::KeyEntry;
#[test]
fn some() {
const KEY: &str = "emoción";
let key = KeyEntry::new(KEY);
assert!(key.is_some());
let key = key.unwrap();
assert_eq!(KEY, key.0);
}
#[test]
fn none() {
let key = KeyEntry::new("");
assert!(key.is_none());
}
}
use std::ops::Deref;
#[test]
fn deref() {
const KEY: &str = "key";
let key = KeyEntry(KEY);
assert_eq!(KEY, key.deref());
}
}
mod insert_crux {
use std::ops::Deref;
use crate::{insert_crux, tra::TraStrain, Entry, KeyEntry, LeftRight, LrTrie, Node};
#[test]
fn basic_test() {
let mut root = Node::empty();
const ENTRY: &str = "lr_branches_inserT";
let limit = ENTRY.len() - 1;
let entry: Entry = KeyEntry(ENTRY);
let node = insert_crux(&mut root, &entry);
assert_eq!('T', node.c);
assert_eq!(None, node.branches);
assert!(root.branches.is_some());
let mut branches = root.branches.as_ref().unwrap();
let mut super_n: *const Node = &root;
for (ix, c) in ENTRY.chars().enumerate() {
let node = branches.get(0);
assert!(node.is_some());
let node = node.unwrap();
assert_eq!(c, node.c);
assert_eq!(super_n, node.supernode);
super_n = node.deref();
if ix < limit {
let temp = &node.branches;
assert!(temp.is_some());
branches = temp.as_ref().unwrap();
} else {
assert!(&node.branches.is_none());
}
}
}
#[test]
fn existing_path_insert() {
const OLD: &str = "touchstone";
const NEW: &str = "touch";
let old = KeyEntry(OLD);
let new = KeyEntry(NEW);
let mut trie = LrTrie::new();
_ = insert_crux(&mut trie.left, &old);
_ = insert_crux(&mut trie.left, &new);
_ = trie.track(&old, LeftRight::Left, TraStrain::TraEmp);
let old_path = trie.cc_trace();
_ = trie.track(&new, LeftRight::Left, TraStrain::TraEmp);
let new_path = trie.cc_trace();
assert_eq!(OLD.len() + 1, old_path.len());
assert_eq!(new_path, old_path[..NEW.len() + 1]);
}
}
mod index_of_c {
use crate::{index_of_c, Branches, Node};
fn branches(cs: &[char]) -> Branches {
cs.iter()
.map(|x| Node::new_boxed(*x, 0 as *const Node))
.collect::<Branches>()
}
#[test]
fn some() {
let branches = branches(&['a', 'b', 'c']);
let index = index_of_c(&branches, 'c');
assert!(index.is_some());
assert_eq!(2, index.unwrap());
}
#[test]
fn none() {
let branches = branches(&['a', 'b', 'c']);
let index = index_of_c(&branches, 'd');
assert!(index.is_none());
}
}
mod cl_lrref {
use crate::{cl_lrref, Branches, Node};
use std::ptr;
#[test]
fn has_to() {
let mut node = Node::empty();
node.lrref = &node;
node.branches = Some(Branches::new());
assert_eq!(true, cl_lrref(&mut node));
assert_eq!(ptr::null(), node.lrref);
}
#[test]
fn has_not_to() {
let mut node = Node::empty();
node.lrref = &node;
assert_eq!(false, cl_lrref(&mut node));
assert_eq!(&node as *const Node, node.lrref);
}
}
mod delete_subnode {
use crate::{delete_subnode, Branches, Node};
use std::{ops::Deref, vec};
#[test]
fn deletion_continues() {
let mut node = Node::empty();
node.branches = Some(vec![Node::empty_boxed()]);
assert_eq!(false, delete_subnode(&mut node, 0));
assert_eq!(None, node.branches);
}
#[test]
fn node_with_branches() {
let mut node = Node::empty();
#[rustfmt::skip]
let branches = vec![
Node::empty_boxed(),
Node::new_boxed('a', 0 as *const Node),
Node::new_boxed('b', 0 as *const Node),
Node::new_boxed('c', 0 as *const Node),
];
node.branches = Some(branches);
assert_eq!(true, delete_subnode(&mut node, 1));
let branches = node.branches.as_ref().unwrap();
assert_eq!(3, branches.len());
assert_eq!(&Node::empty(), branches[0].deref());
assert_eq!('c', branches[1].c);
assert_eq!('b', branches[2].c);
}
#[test]
fn key_node() {
let mut node = Node::empty();
node.branches = Some(vec![Node::empty_boxed()]);
node.lrref = &node;
assert_eq!(true, delete_subnode(&mut node, 0));
assert_eq!(None, node.branches);
}
#[test]
#[should_panic(expected = "swap_remove index (is 0) should be < len (is 0)")]
fn index_out_of_bounds() {
let mut node = Node::empty();
node.branches = Some(Branches::new());
delete_subnode(&mut node, 0);
}
}
mod delete_key_side {
use crate::{delete_key_side, Branches, Node, PathNode};
use std::{ops::DerefMut, ptr};
#[test]
fn keynode_with_branches() {
let mut n = Node::empty();
n.lrref = &n;
n.branches = Some(Branches::new());
#[rustfmt::skip]
let path = vec![
PathNode(usize::MAX, &mut n),
PathNode(usize::MAX, &mut n)
];
delete_key_side(&path);
assert_eq!(ptr::null(), n.lrref);
}
#[test]
fn node_with_branches() {
let mut empty_n = Node::empty();
let mut n = Node::empty();
n.branches = Some(vec![Node::empty_boxed(), Node::empty_boxed()]);
#[rustfmt::skip]
let path = vec![
PathNode(usize::MAX, &mut empty_n),
PathNode(usize::MAX, &mut n),
PathNode(1, &mut empty_n),
];
delete_key_side(&path);
assert_eq!(1, n.branches.as_ref().unwrap().len());
}
#[test]
fn node_being_keyentry() {
let mut empty_n = Node::empty();
let mut n1 = Node::empty();
n1.lrref = &n1;
n1.branches = Some(vec![Node::empty_boxed()]);
let mut n2 = Node::empty();
n2.branches = Some(vec![Node::empty_boxed()]);
#[rustfmt::skip]
let path = vec![
PathNode(usize::MAX, &mut empty_n),
PathNode(usize::MAX, &mut n1),
PathNode(0, &mut n2),
PathNode(0, &mut empty_n),
];
delete_key_side(&path);
assert_eq!(false, n1.branches());
assert_eq!(false, n2.branches());
}
#[test]
fn root_escape() {
let mut root = Node::empty();
let node = Node::new_boxed('a', &root);
root.branches = Some(vec![node]);
#[rustfmt::skip]
let path = vec![
PathNode(usize::MAX, &mut root),
PathNode(0, root.branches.as_mut().unwrap()[0].deref_mut()),
];
delete_key_side(&path);
assert_eq!(None, root.branches);
}
}
mod delete_entry_side {
use crate::{delete_entry_side, Branches, Node};
use std::{ops::Deref, ptr};
#[test]
fn keynode_with_branches() {
let mut n = Node::empty();
n.supernode = &n;
n.lrref = &n;
n.branches = Some(Branches::new());
delete_entry_side(&n);
assert_eq!(ptr::null(), n.lrref);
}
#[test]
fn node_with_branches() {
let mut n = Node::empty();
n.supernode = &n;
n.branches = Some(vec![Node::new_boxed('a', &n), Node::empty_boxed()]);
let mut ks_en = Node::empty();
ks_en.lrref = n.branches.as_ref().unwrap()[0].deref();
delete_entry_side(&ks_en);
let branches = n.branches.as_ref();
assert!(branches.is_some());
let branches = branches.unwrap();
assert_eq!(1, branches.len());
assert_eq!('\0', branches[0].c);
}
#[test]
fn node_being_keyentry() {
let mut n = Node::empty();
n.supernode = &n;
n.branches = Some(vec![Node::new_boxed('a', &n)]);
n.lrref = &n;
let mut ks_en = Node::empty();
ks_en.lrref = n.branches.as_ref().unwrap()[0].deref();
delete_entry_side(&ks_en);
assert_eq!(None, n.branches);
}
#[test]
fn root_escape() {
let mut root = Node::empty();
let node = Node::new_boxed('a', &root);
root.branches = Some(vec![node]);
let mut ks_en = Node::empty();
ks_en.lrref = root.branches.as_ref().unwrap()[0].deref();
delete_entry_side(&ks_en);
assert_eq!(None, root.branches);
}
}
mod set_cap {
use crate::{set_cap, UC};
#[test]
fn extend() {
let new_cap = 10;
let mut buf = UC::new(Vec::<usize>::new());
assert!(buf.capacity() < new_cap);
let size = set_cap(&mut buf, new_cap);
assert!(size >= new_cap);
assert!(buf.capacity() >= new_cap);
}
#[test]
fn shrink() {
let new_cap = 10;
let old_cap = 50;
let mut buf = UC::new(Vec::<usize>::with_capacity(old_cap));
let size = set_cap(&mut buf, new_cap);
assert!(size >= new_cap && size < old_cap);
let cap = buf.capacity();
assert!(cap >= new_cap && cap < old_cap);
}
#[test]
fn same() {
let cap = 10;
let mut buf = UC::new(Vec::<usize>::new());
assert!(buf.capacity() < cap);
buf.reserve_exact(cap);
let cap = buf.capacity();
let size = set_cap(&mut buf, cap);
assert_eq!(cap, size);
assert_eq!(cap, buf.capacity());
}
}
mod ext {
use crate::{ext, KeyEntry, LrTrie};
#[test]
fn basic_test() {
let proof = [("opalescence", "black locust"), ("olivewood", "limehound")];
let mut trie = LrTrie::new();
for es in proof {
trie.insert(&KeyEntry(es.0), &KeyEntry(es.1));
}
let mut k_buf = String::new();
let mut e_buf = Vec::new();
let mut res = Vec::new();
let branches = trie.left.branches.as_ref().unwrap();
ext(branches, &mut k_buf, &mut e_buf, &mut res);
assert_eq!(2, res.len());
for z in proof.iter().zip(res.iter()) {
let p = z.0;
let t = z.1;
assert_eq!(p.0, t.0);
assert_eq!(p.1, t.1);
}
assert_eq!(0, k_buf.len());
assert_eq!(0, e_buf.len());
}
#[test]
fn load() {
let proof = [
("olivenite", "limelight"),
("olivewood", "limehound"),
("olivary", "limestone"),
("oligotrophic", "limescale"),
("lemon", "bandoline"),
("lemonade", "podium"),
("lemon balm", "platina"),
("tapestry", "platform"),
("lemongrass", "rostrum"),
("temperate", "region"),
("tapis", "constituent"),
("cheque", "constellation"),
("season", "crops"),
("array", "formation"),
("glassware", "glasswork"),
];
let mut trie = LrTrie::new();
for es in proof {
trie.insert(&KeyEntry(es.0), &KeyEntry(es.1));
}
let mut k_buf = String::new();
let mut e_buf = Vec::new();
let mut res = Vec::new();
let branches = trie.right.branches.as_ref().unwrap();
ext(branches, &mut k_buf, &mut e_buf, &mut res);
assert_eq!(proof.len(), res.len());
for z in proof.iter().zip(res.iter()) {
let p = z.0;
let t = z.1;
assert_eq!(p.1, t.0, "{}", p.0);
assert_eq!(p.0, t.1, "{}", p.1);
}
}
}
mod construct_e {
use crate::{construct_e, Node};
#[test]
fn construction() {
let root = Node::empty();
let n1 = Node::new('l', &root);
let n2 = Node::new('r', &n1);
let n3 = Node::new('_', &n2);
let n4 = Node::new('t', &n3);
let n5 = Node::new('r', &n4);
let n6 = Node::new('i', &n5);
let n7 = Node::new('e', &n6);
let mut buf = Vec::new();
let res = construct_e(&n7, &mut buf);
assert_eq!("lr_trie", res.as_str());
assert_eq!(0, buf.len());
}
#[test]
fn root_escape() {
let mut root = Node::empty();
root.c = 'r';
let mut buf = Vec::new();
let res = construct_e(&root, &mut buf);
assert_eq!("", res.as_str());
assert_eq!(0, buf.len());
assert_eq!(0, buf.capacity());
}
}
mod trie {
use crate::{LeftRight, LrTrie, Node};
#[test]
fn new() {
let trie = LrTrie::new();
let empty = Node::empty();
assert_eq!(empty, trie.left);
assert_eq!(empty, trie.right);
assert_eq!(0, trie.trace.len());
assert_eq!(0, trie.entry.len());
assert_eq!(0, trie.count);
}
mod insert {
use crate::{Branches, Entry, Key, KeyEntry, LeftRight, LrTrie, Node};
fn last_node(branches: &Branches) -> &Node {
let node = branches.get(0);
assert!(node.is_some());
let mut node = node.unwrap();
while let Some(b) = node.branches.as_ref() {
let n = b.get(0);
assert!(n.is_some());
node = n.as_ref().unwrap();
}
node
}
fn insert(trie: &mut LrTrie, lke: &Entry, rke: &Entry) -> (*const Node, *const Node) {
trie.insert(lke, rke);
let l_branches = &trie.left.branches.as_ref().unwrap();
let r_branches = &trie.right.branches.as_ref().unwrap();
(last_node(l_branches), last_node(r_branches))
}
fn put_id(node: *const Node, val: usize) {
let node = node.cast_mut();
Node::as_mut(node).id = val;
}
#[test]
fn basic_test() {
let left_ke = &KeyEntry("LEFT");
let right_ke = &KeyEntry("RIGHT");
let trie = &mut LrTrie::new();
trie.insert(left_ke, right_ke);
assert_eq!(1, trie.count);
let left = verify(trie, left_ke, LeftRight::Left, right_ke);
let right = verify(trie, right_ke, LeftRight::Right, left_ke);
assert_eq!(left.lrref, right as *const Node);
assert_eq!(right.lrref, left as *const Node);
fn verify<'a>(trie: &'a LrTrie, key: &Key, lr: LeftRight, e: &Entry) -> &'a Node {
let member = trie.member(key, lr.clone());
assert!(member.is_some());
assert_eq!(e.0, &member.unwrap());
last_node(trie.branches(lr).unwrap())
}
}
#[test]
fn reinsert_same() {
#[rustfmt::skip]
let duos = [
("LEFT", "RIGHT"),
("L", "R"),
("LEFT", "R"),
("L", "RIGHT")
];
for d in duos {
let left_ke = &KeyEntry(d.0);
let right_ke = &KeyEntry(d.1);
let trie = &mut LrTrie::new();
let (lln_a_ptr, rln_a_ptr) = insert(trie, left_ke, right_ke);
assert_eq!(1, trie.count);
put_id(lln_a_ptr, 1);
put_id(rln_a_ptr, 2);
let (lln_b_ptr, rln_b_ptr) = insert(trie, left_ke, right_ke);
assert_eq!(1, trie.count);
let lln_b_ref = Node::as_ref(lln_b_ptr);
let rln_b_ref = Node::as_ref(rln_b_ptr);
assert_eq!(1, lln_b_ref.id); assert_ne!(2, rln_b_ref.id); assert_eq!(0, rln_b_ref.id);
verify(trie, left_ke, LeftRight::Left, right_ke);
verify(trie, right_ke, LeftRight::Right, left_ke);
fn verify(trie: &LrTrie, key: &Key, lr: LeftRight, e: &Entry) {
let member = trie.member(key, lr);
assert!(member.is_some());
assert_eq!(e.0, member.unwrap());
}
}
}
#[test]
fn reinsert_different() {
#[rustfmt::skip]
let triplets = [
("ONE", "ANOTHER", "REPLACEMENT"),
("ONE", "A", "R"),
("ONE", "ANOTHER", "R"),
("ONE", "A", "REPLACEMENT"),
("O", "ANOTHER", "REPLACEMENT"),
("O", "A", "R"),
("O", "A", "REPLACEMENT"),
("O", "ANOTHER", "R"),
];
for t in triplets {
let one = &KeyEntry(t.0);
let another = &KeyEntry(t.1);
let replacement = &KeyEntry(t.2);
for lr in [LeftRight::Left, LeftRight::Right] {
let trie = &mut LrTrie::new();
let (lln_a_ptr, rln_a_ptr) = insert(trie, one, another);
assert_eq!(1, trie.count);
put_id(lln_a_ptr, 97);
put_id(rln_a_ptr, 98);
let (lln_b_ptr, rln_b_ptr) = if lr == LeftRight::Left {
insert(trie, replacement, another)
} else {
insert(trie, one, replacement)
};
assert_eq!(1, trie.count);
let (lln_b_ref, rln_b_ref) =
(Node::as_ref(lln_b_ptr), Node::as_ref(rln_b_ptr));
let (kept, removed) = if lr == LeftRight::Left {
assert_eq!(0, lln_b_ref.id);
assert_eq!(98, rln_b_ref.id);
(another, one)
} else {
assert_eq!(97, lln_b_ref.id);
assert_eq!(0, rln_b_ref.id);
(one, another)
};
assert!(trie.member(replacement, lr.clone()).is_some());
assert!(trie.member(kept, lr.clone().invert()).is_some());
assert!(trie.member(removed, lr).is_none());
}
}
}
#[test]
fn entry_map_merge() {
let mut trie = LrTrie::new();
let a1 = &KeyEntry("A1");
let a2 = &KeyEntry("A2");
let b1 = &KeyEntry("B1");
let b2 = &KeyEntry("B2");
trie.insert(a1, b1);
trie.insert(b2, a2);
assert_eq!(2, trie.count);
trie.insert(a1, a2);
assert_eq!(1, trie.count);
assert_eq!(Some(a2.0.to_string()), trie.member(a1, LeftRight::Left));
assert_eq!(Some(a1.0.to_string()), trie.member(a2, LeftRight::Right));
assert_eq!(None, trie.member(b1, LeftRight::Right));
assert_eq!(None, trie.member(b2, LeftRight::Left));
}
}
mod track {
use crate::{KeyEntry, LeftRight, LrTrie, Node, TraRes, TraStrain};
#[test]
fn tracing() {
let mut trie = LrTrie::new();
let entries = ["key", "keyword", "keyboard", "keyhole"];
let entries = entries.map(|x| KeyEntry(x));
for e in entries.iter() {
trie.insert(&e, &e);
}
let keyword = &entries[1];
_ = trie.track(keyword, LeftRight::Left, TraStrain::TraEmp);
let trace = trie.cc_trace();
assert_eq!(keyword.0.len() + 1, trace.len());
let l_root: *const Node = &trie.left;
assert_eq!(l_root as usize, trace[0].1 as usize);
for k in entries[0..2].iter() {
let s = k.0;
for (ix, c) in s.chars().enumerate() {
let pn = &trace[ix + 1];
assert_eq!(0, pn.0);
let n = pn.n_ref();
assert_eq!(c, n.c);
}
let en = &trace[s.len()].n_ref();
assert_eq!(true, en.lrref());
}
_ = trie.track(&entries[3], LeftRight::Left, TraStrain::TraEmp);
let trace = trie.cc_trace();
let h_node = &trace[4];
assert_eq!('h', h_node.n_ref().c);
assert_eq!(2, h_node.0);
}
#[test]
fn ok() {
let entry = &KeyEntry("información meteorológica");
let mut trie = LrTrie::new();
_ = trie.insert(entry, entry);
let res = trie.track(entry, LeftRight::Left, TraStrain::NonEmp);
match res {
TraRes::Ok => {}
_ => panic!("Not `TraRes::Ok`, but {:?}.", res),
}
}
#[test]
fn ok_ref() {
let entry = &KeyEntry("información meteorológica X");
let mut trie = LrTrie::new();
_ = trie.insert(entry, entry);
let res = trie.track(entry, LeftRight::Left, TraStrain::NonRef);
match res {
TraRes::OkRef(n) => {
assert_eq!(true, n.lrref());
assert_eq!('X', n.c);
}
_ => panic!("Not `TraRes::OkRef(_)`, but {:?}.", res),
}
}
#[test]
#[should_panic(expected = "Unsupported result scenario.")]
fn unsupported_result() {
let entry = &KeyEntry("información meteorológica");
let mut trie = LrTrie::new();
_ = trie.insert(entry, entry);
_ = trie.track(entry, LeftRight::Left, TraStrain::NonMut);
}
#[test]
fn unknown_not_path() {
let entry = &KeyEntry("wordbook");
let key = &KeyEntry("wordbooks");
let mut trie = LrTrie::new();
_ = trie.insert(entry, entry);
let res = trie.track(key, LeftRight::Left, TraStrain::NonEmp);
assert_eq!(TraRes::UnknownForAbsentPathBranches, res);
}
#[test]
fn unknown_not_path2() {
let entry = &KeyEntry("wordbookz");
let key = &KeyEntry("wordbooks");
let mut trie = LrTrie::new();
_ = trie.insert(entry, entry);
let res = trie.track(key, LeftRight::Left, TraStrain::NonEmp);
assert_eq!(TraRes::UnknownForAbsentPathNode, res);
}
#[test]
fn unknown_not_entry() {
let entry = &KeyEntry("wordbooks");
let key = &KeyEntry("wordbook");
let mut trie = LrTrie::new();
_ = trie.insert(entry, entry);
let res = trie.track(key, LeftRight::Left, TraStrain::NonEmp);
assert_eq!(TraRes::UnknownForNotEntry, res);
}
}
mod member {
use crate::{Entry, Key, KeyEntry, LeftRight, LrTrie};
#[test]
fn member() {
let left_ke = KeyEntry("LEFT");
let right_ke = KeyEntry("RIGHT");
let mut trie = LrTrie::new();
trie.insert(&left_ke, &right_ke);
assert_eq!(0, trie.entry.capacity());
verify(&left_ke, LeftRight::Left, &right_ke, &trie);
verify(&right_ke, LeftRight::Right, &left_ke, &trie);
fn verify(key: &Key, lr: LeftRight, e: &Entry, trie: &LrTrie) {
let entry = trie.member(key, lr);
assert!(entry.is_some());
assert_eq!(e.0, &entry.unwrap());
assert_eq!(0, trie.entry.len());
assert_eq!(true, trie.entry.capacity() > 0);
}
}
#[test]
fn not_member() {
let keyword = KeyEntry("Keyword");
let mut trie = LrTrie::new();
trie.insert(&keyword, &keyword);
for lr in [LeftRight::Left, LeftRight::Right] {
for key in ["Key", "Opener"] {
let key = KeyEntry(key);
let member = trie.member(&key, lr.clone());
assert!(member.is_none());
}
}
}
}
use crate::aide::address;
#[test]
fn root() {
let trie = LrTrie::new();
let left = address(&trie.left);
let right = address(&trie.right);
let vals = [(left, LeftRight::Left), (right, LeftRight::Right)];
for v in vals {
let test = address(trie.root(v.1));
assert_eq!(v.0, test);
}
}
use crate::Branches;
#[test]
fn branches() {
let mut trie = LrTrie::new();
let l_proof = address(trie.left.branches.get_or_insert(Branches::new()));
let r_proof = address(trie.right.branches.get_or_insert(Branches::new()));
let l_test = address(trie.branches(LeftRight::Left).unwrap());
let r_test = address(trie.branches(LeftRight::Right).unwrap());
assert_eq!(l_proof, l_test);
assert_eq!(r_proof, r_test);
}
mod delete {
use std::ops::Deref;
use crate::{tra::TraStrain, Key, KeyEntry, LeftRight, LrTrie};
#[test]
fn known_unknown() {
let known = &KeyEntry("plainoperator");
let unknown = &KeyEntry("secretagent");
let mut trie = LrTrie::new();
_ = trie.insert(&known, &known);
assert_eq!(Err(()), trie.delete(&unknown, LeftRight::Left));
assert_eq!(0, trie.trace.len());
assert_eq!(1, trie.count);
assert_eq!(Ok(()), trie.delete(&known, LeftRight::Left));
assert_eq!(0, trie.trace.len());
assert_eq!(0, trie.count);
assert_eq!(None, trie.member(&known, LeftRight::Right));
}
#[test]
fn inner_entry() {
let mut trie = LrTrie::new();
let outer = KeyEntry("Keyword");
trie.insert(&outer, &outer);
for lr in [LeftRight::Left, LeftRight::Right] {
let inner = KeyEntry("Key");
trie.insert(&inner, &inner);
assert!(trie.delete(&inner, lr).is_ok());
assert!(trie.member(&inner, LeftRight::Left).is_none());
assert!(trie.member(&inner, LeftRight::Right).is_none());
assert!(trie.member(&outer, LeftRight::Left).is_some());
assert!(trie.member(&outer, LeftRight::Right).is_some());
}
}
#[test]
fn branching_node() {
let keyword = KeyEntry("Keyword");
let keyboard = KeyEntry("Keyboard");
let keypad = KeyEntry("Keypad");
let key: Key = KeyEntry("Key");
for lr in [LeftRight::Left, LeftRight::Right] {
let mut trie = LrTrie::new();
trie.insert(&keyword, &keyword);
trie.insert(&keyboard, &keyboard);
trie.insert(&keypad, &keypad);
assert!(trie.delete(&keyboard, lr).is_ok());
for lr in [LeftRight::Left, LeftRight::Right] {
assert!(trie.member(&keyboard, lr.clone()).is_none());
assert!(trie.member(&keyword, lr.clone()).is_some());
assert!(trie.member(&keypad, lr.clone()).is_some());
_ = trie.track(&key, lr, TraStrain::TraEmp);
let y_node = trie.trace[key.0.len()].n_ref();
let branches = y_node.branches.as_ref().unwrap();
assert_eq!(2, branches.len());
let filtered = branches.iter().filter(|x| x.c == 'w' || x.c == 'p').count();
assert_eq!(2, filtered);
}
}
}
#[test]
fn branches_removal() {
let keyword = KeyEntry("Keyword");
let mut trie = LrTrie::new();
for lr in [LeftRight::Left, LeftRight::Right] {
trie.insert(&keyword, &keyword);
assert!(trie.delete(&keyword, lr.clone()).is_ok());
assert!(trie.member(&keyword, lr.clone()).is_none());
assert!(trie.member(&keyword, lr.invert()).is_none());
assert!(trie.branches(LeftRight::Left).is_none());
assert!(trie.branches(LeftRight::Right).is_none());
}
}
#[test]
fn node_composing_path() {
let dissimilar = KeyEntry("Dissimilar");
let keyword = KeyEntry("Keyword");
for lr in [LeftRight::Left, LeftRight::Right] {
let mut trie = LrTrie::new();
trie.insert(&dissimilar, &dissimilar);
trie.insert(&keyword, &keyword);
assert!(trie.delete(&keyword, lr.clone()).is_ok());
assert!(trie.member(&keyword, lr.clone()).is_none());
assert!(trie.member(&dissimilar, lr).is_some());
}
}
#[test]
fn node_being_keyentry() {
let keyword = KeyEntry("Keyword");
let k = KeyEntry("K");
let mut trie = LrTrie::new();
trie.insert(&k, &k);
for lr in [LeftRight::Left, LeftRight::Right] {
trie.insert(&keyword, &keyword);
assert!(trie.delete(&keyword, lr.clone()).is_ok());
assert!(trie.member(&keyword, lr.clone()).is_none());
assert!(trie.member(&k, lr.clone()).is_some());
let branches = trie.branches(lr);
let k = &branches.unwrap()[0];
assert_eq!(false, k.branches());
}
}
#[test]
fn one_letter_a() {
let keyword = KeyEntry("Keyword");
let k = KeyEntry("K");
let mut trie = LrTrie::new();
trie.insert(&keyword, &keyword);
for lr in [LeftRight::Left, LeftRight::Right] {
trie.insert(&k, &k);
assert!(trie.delete(&k, lr.clone()).is_ok());
assert!(trie.member(&k, lr.clone()).is_none());
assert!(trie.member(&keyword, lr.clone()).is_some());
let branches = trie.branches(lr);
let k = branches.unwrap()[0].deref();
assert_eq!('K', k.c);
assert_eq!(true, k.branches());
}
}
#[test]
fn one_letter_b() {
let c = KeyEntry("C");
let k = KeyEntry("K");
let mut trie = LrTrie::new();
trie.insert(&c, &c);
for lr in [LeftRight::Left, LeftRight::Right] {
trie.insert(&k, &k);
assert!(trie.delete(&k, lr.clone()).is_ok());
assert!(trie.member(&k, lr.clone()).is_none());
assert!(trie.member(&c, lr.clone()).is_some());
let branches = trie.branches(lr);
let c = branches.unwrap()[0].deref();
assert_eq!('C', c.c);
}
}
}
mod put_buf_cap {
use crate::{Buffer, LrTrie};
#[test]
fn trace() {
let mut trie = LrTrie::new();
assert_eq!(0, trie.trace.capacity());
let cap = 100;
let size = trie.put_buf_cap(cap, Buffer::Delete);
assert_eq!(true, size >= cap);
assert_eq!(true, trie.trace.capacity() >= cap);
}
#[test]
fn entry() {
let mut trie = LrTrie::new();
assert_eq!(0, trie.entry.capacity());
let cap = 100;
let size = trie.put_buf_cap(cap, Buffer::Member);
assert_eq!(true, size >= cap);
assert_eq!(true, trie.entry.capacity() >= cap);
}
}
mod aq_buf_cap {
use crate::{Buffer, LrTrie};
#[test]
fn trace() {
let cap = 10;
let mut trie = LrTrie::new();
let buf = &mut trie.trace;
assert!(buf.capacity() < cap);
buf.reserve_exact(cap);
let cap = buf.capacity();
assert_eq!(cap, trie.aq_buf_cap(Buffer::Delete));
}
#[test]
fn entry() {
let cap = 10;
let mut trie = LrTrie::new();
let buf = &mut trie.entry;
assert!(buf.capacity() < cap);
buf.reserve_exact(cap);
let cap = buf.capacity();
assert_eq!(cap, trie.aq_buf_cap(Buffer::Member));
}
}
}
use crate::KeyEntry;
#[test]
fn clear() {
let mut trie = LrTrie::new();
let entry = KeyEntry("Key");
trie.insert(&entry, &entry);
assert_eq!(1, trie.clear());
assert_eq!(0, trie.count);
assert_eq!(trie.left, Node::empty());
assert_eq!(trie.right, Node::empty());
}
#[test]
fn count() {
let mut trie = LrTrie::new();
assert_eq!(0, trie.count());
trie.count = 99;
assert_eq!(99, trie.count());
}
mod extract {
use crate::{KeyEntry, LeftRight, LrTrie};
#[test]
fn left() {
let proof = [
("olivenite", "limelight"),
("olivewood", "limehound"),
("tapestry", "platform"),
("lemonade", "podium"),
("lemongrass", "rostrum"),
("cheque", "constellation"),
("array", "formation"),
];
let mut trie = LrTrie::new();
for es in proof {
trie.insert(&KeyEntry(es.0), &KeyEntry(es.1));
}
let ext = trie.extract(LeftRight::Left);
assert_eq!(true, ext.is_some());
let ext = ext.unwrap();
let proof_len = proof.len();
assert_eq!(proof_len, ext.len());
assert_eq!(true, ext.capacity() >= proof_len);
for z in proof.iter().zip(ext.iter()) {
let p = z.0;
let l = z.1;
assert_eq!(p.0, l.0);
assert_eq!(p.1, l.1);
}
}
#[test]
fn right() {
let proof = [
("olivenite", "limelight"),
("olivewood", "limehound"),
("lemon", "bandoline"),
("lemonade", "podium"),
("lemon balm", "platina"),
("cheque", "constellation"),
("season", "crops"),
];
let mut trie = LrTrie::new();
for es in proof {
trie.insert(&KeyEntry(es.0), &KeyEntry(es.1));
}
let ext = trie.extract(LeftRight::Right);
assert_eq!(true, ext.is_some());
let ext = ext.unwrap();
let proof_len = proof.len();
assert_eq!(proof_len, ext.len());
assert_eq!(true, ext.capacity() >= proof_len);
for z in proof.iter().zip(ext.iter()) {
let p = z.0;
let r = z.1;
assert_eq!(p.0, r.1);
assert_eq!(p.1, r.0);
}
}
#[test]
fn empty() {
let trie = LrTrie::new();
assert_eq!(None, trie.extract(LeftRight::Right));
assert_eq!(None, trie.extract(LeftRight::Left));
}
}
mod as_ref {
use crate::aide::address;
use crate::{KeyEntry, LrTrie};
#[test]
fn empty_tree() {
let trie = LrTrie::new();
let as_ref = trie.as_ref();
assert_eq!(None, as_ref);
}
#[test]
fn non_empty_tree() {
let mut trie = LrTrie::new();
let key = KeyEntry("0");
_ = trie.insert(&key, &key);
let root_branches = trie.as_ref().unwrap();
let l_test = address(root_branches.0);
let r_test = address(root_branches.1);
let l_proof = address(trie.left.branches.as_ref().unwrap());
let r_proof = address(trie.right.branches.as_ref().unwrap());
assert_eq!(l_test, l_proof);
assert_eq!(r_test, r_proof);
}
}
mod as_mut {
use crate::aide::address;
use crate::{KeyEntry, LrTrie};
#[test]
fn empty_tree() {
let mut trie = LrTrie::new();
let as_mut = trie.as_mut();
assert_eq!(None, as_mut);
}
#[test]
fn non_empty_tree() {
let mut trie = LrTrie::new();
let key = KeyEntry("0");
_ = trie.insert(&key, &key);
let root_branches = trie.as_mut().unwrap();
let l_test = address(root_branches.0);
let r_test = address(root_branches.1);
let l_proof = address(trie.left.branches.as_mut().unwrap());
let r_proof = address(trie.right.branches.as_mut().unwrap());
assert_eq!(l_test, l_proof);
assert_eq!(r_test, r_proof);
}
}
#[test]
fn load_1() {
const P_LEN: usize = 15;
let proof: [(&str, &str); P_LEN] = [
("olivenite", "limelight"),
("olivewood", "limehound"),
("olivary", "limestone"),
("oligotrophic", "limescale"),
("lemon", "bandoline"),
("lemonade", "podium"),
("lemongrass", "rostrum"),
("lemon balm", "platina"),
("tapestry", "platform"),
("tapis", "constituent"),
("temperate", "region"),
("cheque", "constellation"),
("array", "formation"),
("season", "crops"),
("glassware", "glasswork"),
];
let mut trie = LrTrie::new();
for es in proof {
trie.insert(&KeyEntry(es.0), &KeyEntry(es.1));
}
for p in proof {
let entry = trie.member(&KeyEntry(p.0), LeftRight::Left);
assert_eq!(p.1, entry.unwrap().as_str());
let entry = trie.member(&KeyEntry(p.1), LeftRight::Right);
assert_eq!(p.0, entry.unwrap().as_str());
}
for i in 0..P_LEN {
if i & 1 == 0 {
assert_eq!(Ok(()), trie.delete(&KeyEntry(proof[i].0), LeftRight::Left));
}
}
for i in 0..P_LEN {
let p = proof[i];
if i & 1 == 1 {
let entry = trie.member(&KeyEntry(p.0), LeftRight::Left);
assert_eq!(p.1, entry.unwrap().as_str());
let entry = trie.member(&KeyEntry(p.1), LeftRight::Right);
assert_eq!(p.0, entry.unwrap().as_str());
} else {
let entry = trie.member(&KeyEntry(p.0), LeftRight::Left);
assert_eq!(true, entry.is_none());
let entry = trie.member(&KeyEntry(p.1), LeftRight::Right);
assert_eq!(true, entry.is_none());
}
}
}
#[test]
fn load_2() {
const P_LEN: usize = 15;
let last_ix = P_LEN - 1;
let proof: [(&str, &str); P_LEN] = [
("olivenite", "limelight"),
("olivewood", "limehound"),
("olivary", "limestone"),
("oligotrophic", "limescale"),
("lemon", "bandoline"),
("lemonade", "podium"),
("lemongrass", "rostrum"),
("lemon balm", "platina"),
("tapestry", "platform"),
("tapis", "constituent"),
("temperate", "region"),
("cheque", "constellation"),
("array", "formation"),
("season", "crops"),
("glassware", "glasswork"),
];
let mut trie = LrTrie::new();
for es in proof {
trie.insert(&KeyEntry(es.0), &KeyEntry(es.1));
}
for p in proof {
let entry = trie.member(&KeyEntry(p.0), LeftRight::Left);
assert_eq!(p.1, entry.unwrap().as_str());
let entry = trie.member(&KeyEntry(p.1), LeftRight::Right);
assert_eq!(p.0, entry.unwrap().as_str());
}
for i in 1..last_ix {
assert_eq!(Ok(()), trie.delete(&KeyEntry(proof[i].1), LeftRight::Right));
}
for i in 1..last_ix {
let p = proof[i];
assert_eq!(None, trie.member(&KeyEntry(p.0), LeftRight::Left));
assert_eq!(None, trie.member(&KeyEntry(p.1), LeftRight::Right));
}
for i in [0, last_ix] {
let p = proof[i];
let entry = trie.member(&KeyEntry(p.0), LeftRight::Left);
assert_eq!(p.1, entry.unwrap().as_str());
let entry = trie.member(&KeyEntry(p.1), LeftRight::Right);
assert_eq!(p.0, entry.unwrap().as_str());
}
}
mod readme {
use crate::{KeyEntry, LeftRight, LrTrie};
#[test]
fn test() {
const ONE: &str = "emoción";
const ANOTHER: &str = "emotion";
const REPLACEMENT: &str = "equilibrio sicofísico";
let mut trie = LrTrie::new();
let one = &KeyEntry::new(ONE).unwrap();
let another = &KeyEntry::new(ANOTHER).unwrap();
let replacement = &KeyEntry::new(REPLACEMENT).unwrap();
trie.insert(one, another);
assert!(trie.member(one, LeftRight::Left).is_some());
assert!(trie.member(another, LeftRight::Left).is_none());
assert!(trie.member(another, LeftRight::Right).is_some());
trie.insert(one, replacement);
assert_eq!(
Some(String::from(REPLACEMENT)),
trie.member(&one, LeftRight::Left)
);
assert!(trie.member(another, LeftRight::Right).is_none());
assert_eq!(
Some(String::from(ONE)),
trie.member(replacement, LeftRight::Right)
);
assert_eq!(Ok(()), trie.delete(one, LeftRight::Left));
assert!(trie.member(one, LeftRight::Left).is_none());
assert!(trie.member(replacement, LeftRight::Right).is_none());
assert_eq!(Err(()), trie.delete(replacement, LeftRight::Right));
}
}
}