use std::collections::VecDeque;
use self::Tree::*;
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum Tree<T: Sized + Eq> {
Zero,
One(T),
Many(VecDeque<Tree<T>>),
}
impl<T: Eq> Tree<T> {
pub fn is_empty(&self) -> bool {
match self {
Tree::Zero => true,
Tree::One(_) => false,
Tree::Many(children) => children.iter().all(|tr| tr.is_empty()),
}
}
}
impl<T: Sized + Eq + 'static> IntoIterator for Tree<T> {
type Item = T;
type IntoIter = std::collections::vec_deque::IntoIter<T>;
fn into_iter(self) -> Self::IntoIter {
self.list().0.into_iter()
}
}
impl<T: Sized + Eq + 'static> Tree<T> {
#[allow(clippy::type_complexity)]
pub fn list(self) -> (VecDeque<T>, Box<dyn Fn(VecDeque<T>) -> Tree<T>>) {
fn flatten<T: Sized + Eq>(t: Tree<T>, xs: VecDeque<T>) -> VecDeque<T> {
match (t, xs) {
(Zero, xs) => xs,
(One(x), mut xs1) => {
xs1.push_back(x);
xs1
}
(Many(ts), xs) => ts.into_iter().fold(xs, |xs, t| flatten(t, xs)),
}
}
#[derive(PartialEq, Eq)]
struct DummyType;
fn construct_dummy_tree<T: Sized + Eq>(t: &Tree<T>) -> Tree<DummyType> {
match t {
Zero => Tree::Zero,
One(_) => Tree::One(DummyType {}),
Many(trees) => Tree::Many(
trees
.iter()
.map(construct_dummy_tree)
.collect::<VecDeque<Tree<DummyType>>>(),
),
}
}
fn recons<T: Sized + Eq>(
old_tree: &Tree<DummyType>,
xs: VecDeque<T>,
) -> (Tree<T>, VecDeque<T>) {
#[allow(clippy::unwrap_used)]
match (old_tree, xs) {
(Zero, xs) => (Zero, xs),
(One(_), mut xs1) => (One(xs1.pop_front().unwrap()), xs1),
(Many(ts), xs) => {
let (ts1, xs1) =
ts.into_iter()
.fold((VecDeque::new(), xs), |(mut ts1, xs), t| {
let (t1, xs1) = recons(t, xs);
ts1.push_back(t1);
(ts1, xs1)
});
(Many(ts1), xs1)
}
}
}
let dummy_tree = construct_dummy_tree(&self);
(
flatten(self, VecDeque::new()),
Box::new(move |xs| recons(&dummy_tree, xs).0),
)
}
pub fn map(self, op: &impl Fn(T) -> T) -> Tree<T> {
match self {
Zero => Zero,
One(t) => One(op(t)),
Many(ts) => Many(ts.into_iter().map(|t| t.map(op)).collect::<_>()),
}
}
}
#[cfg(test)]
mod tests {
use std::iter::zip;
use proptest::prelude::*;
use super::*;
#[allow(dead_code)]
fn proptest_integer_trees() -> impl Strategy<Value = Tree<i32>> {
let leaf = prop_oneof![Just(Tree::Zero), any::<i32>().prop_map(Tree::One),];
leaf.prop_recursive(
10, 512, 20, |inner| proptest::collection::vec_deque(inner.clone(), 0..20).prop_map(Tree::Many),
)
}
proptest! {
#[test]
fn list_is_isomorphic(tree in proptest_integer_trees()) {
let (children,func) = tree.clone().list();
let new_tree = func(children);
prop_assert_eq!(new_tree,tree);
}
#[test]
fn map_add(tree in proptest_integer_trees(), diff in -100i32..100i32) {
let new_tree = tree.clone().map(&|a| a+diff);
let (old_children,_) = tree.list();
let (new_children,_) = new_tree.list();
for (old,new) in zip(old_children,new_children) {
prop_assert_eq!(old+diff,new);
}
}
}
#[test]
fn list_preserves_ordering() {
let my_tree: Tree<i32> = Many(VecDeque::from([
Many(VecDeque::from([One(0), Zero])),
Many(VecDeque::from([Many(VecDeque::from([
Zero,
One(1),
One(2),
]))])),
One(3),
Zero,
One(4),
]));
let flat = my_tree.list().0;
for i in 0..5 {
assert_eq!(flat[i], i.try_into().unwrap());
}
}
}