use super::holes::HolesIterBi;
use super::{Uniplate, context::ContextIterBi};
use std::collections::VecDeque;
pub use crate::Tree;
pub trait Biplate<To>
where
Self: Sized + Clone + Eq + Uniplate + 'static,
To: Sized + Clone + Eq + Uniplate + 'static,
{
fn biplate(&self) -> (Tree<To>, Box<dyn Fn(Tree<To>) -> Self>);
fn with_children_bi(&self, children: VecDeque<To>) -> Self {
let (old_children, ctx) = self.biplate();
let (old_children_lst, rebuild) = old_children.list();
if old_children_lst.len() != children.len() {
panic!("with_children() given an unexpected amount of children");
} else {
ctx(rebuild(children))
}
}
fn descend_bi(&self, op: &impl Fn(To) -> To) -> Self {
let (children, ctx) = self.biplate();
ctx(children.map(op))
}
fn universe_bi(&self) -> VecDeque<To> {
self.children_bi()
.into_iter()
.flat_map(|child| child.universe())
.collect()
}
fn children_bi(&self) -> VecDeque<To> {
self.biplate().0.list().0
}
fn transform_bi(&self, op: &impl Fn(To) -> To) -> Self {
self.descend_bi(&|x| x.transform(op))
}
fn holes_bi(&self) -> impl Iterator<Item = (To, impl Fn(To) -> Self)> {
HolesIterBi::new(self.clone())
}
fn contexts_bi(&self) -> impl Iterator<Item = (To, impl Fn(To) -> Self)> {
ContextIterBi::new(self.clone())
}
}
#[cfg(test)]
mod tests {
use proptest::prelude::*;
use crate::test_common::paper::{Expr, Stmt, proptest_stmts};
use super::*;
proptest! {
#[test]
fn test_context_bi_same_as_universe_bi(ast in proptest_stmts()) {
prop_assert_eq!(Biplate::<Expr>::universe_bi(&ast),Biplate::<Expr>::contexts_bi(&ast).map(|(elem,_)| elem).collect::<VecDeque<_>>());
prop_assert_eq!(Biplate::<Stmt>::universe_bi(&ast),Biplate::<Stmt>::contexts_bi(&ast).map(|(elem,_)| elem).collect::<VecDeque<_>>());
}
#[test]
fn test_context_bi_isomorphic(ast in proptest_stmts()) {
for (e,c) in Biplate::<Expr>::contexts_bi(&ast) {
prop_assert_eq!(c(e.clone()),ast.clone())
}
}
#[test]
fn test_holes_bi_same_as_children_bi(ast in proptest_stmts()) {
prop_assert_eq!(Biplate::<Expr>::children_bi(&ast),Biplate::<Expr>::holes_bi(&ast).map(|(elem,_)| elem).collect::<VecDeque<_>>());
prop_assert_eq!(Biplate::<Stmt>::children_bi(&ast),Biplate::<Stmt>::holes_bi(&ast).map(|(elem,_)| elem).collect::<VecDeque<_>>());
}
}
}