uniplate 0.4.6

Simple, boilerplate-free operations on tree-shaped data types
Documentation
use crate::Uniplate;

// Examples found in the Uniplate paper.

// Stmt and Expr to demonstrate and test multitype traversals.
#[derive(Eq, PartialEq, Clone, Debug, Uniplate)]
#[biplate(to=Expr)]
#[biplate(to=String,)]
pub enum Stmt {
    Assign(String, Expr),
    Sequence(Vec<Stmt>),
    If(Expr, Box<Stmt>, Box<Stmt>),
    While(Expr, Box<Stmt>),
}

#[derive(Eq, PartialEq, Clone, Debug, Uniplate)]
#[biplate(to=String)]
#[biplate(to=Stmt)]
pub enum Expr {
    Add(Box<Expr>, Box<Expr>),
    Sub(Box<Expr>, Box<Expr>),
    Mul(Box<Expr>, Box<Expr>),
    Div(Box<Expr>, Box<Expr>),
    Val(i32),
    Var(String),
    Neg(Box<Expr>),
}

#[cfg(test)]
pub use proptest::*;

#[cfg(test)]
mod proptest {
    use super::Expr;
    use super::Expr::*;
    use super::Stmt;
    use super::Stmt::*;
    use crate::Uniplate;
    use proptest::prelude::*;
    pub fn proptest_exprs() -> impl Strategy<Value = Expr> {
        let leafs = prop_oneof![any::<i32>().prop_map(Val), "[a-z]*".prop_map(Var),];

        leafs.prop_recursive(8, 256, 10, |inner| {
            prop_oneof![
                prop::collection::vec(inner.clone(), 2..3)
                    .prop_map(|elems| Add(Box::new(elems[0].clone()), Box::new(elems[1].clone()))),
                prop::collection::vec(inner.clone(), 2..3)
                    .prop_map(|elems| Sub(Box::new(elems[0].clone()), Box::new(elems[1].clone()))),
                prop::collection::vec(inner.clone(), 2..3)
                    .prop_map(|elems| Mul(Box::new(elems[0].clone()), Box::new(elems[1].clone()))),
                prop::collection::vec(inner.clone(), 2..3)
                    .prop_map(|elems| Div(Box::new(elems[0].clone()), Box::new(elems[1].clone()))),
                inner.prop_map(|inner| Neg(Box::new(inner.clone())))
            ]
        })
    }

    pub fn proptest_stmts() -> impl Strategy<Value = Stmt> {
        let leafs = prop_oneof![("[a-z]*", proptest_exprs()).prop_map(|(a, b)| Assign(a, b)),];

        leafs.prop_recursive(8, 256, 10, |inner| {
            prop_oneof![
                (proptest_exprs(), prop::collection::vec(inner.clone(), 2..4)).prop_map(
                    move |(expr, stmts)| If(
                        expr,
                        Box::new(stmts[0].clone()),
                        Box::new(stmts[1].clone())
                    )
                ),
                (proptest_exprs(), inner.clone())
                    .prop_map(move |(expr, stmt)| While(expr, Box::new(stmt))),
                prop::collection::vec(inner.clone(), 0..10).prop_map(Sequence)
            ]
        })
    }

    proptest! {

    #![proptest_config(ProptestConfig { max_shrink_iters:1000000, max_global_rejects:100000,cases:50,..Default::default()})]

    #[test]
    fn uniplate_children(ast in proptest_stmts(), new_children in proptest::collection::vec(proptest_stmts(),1..=10)) {
        use std::collections::VecDeque;
        let original_children = ast.children();
        prop_assume!(original_children.len() == new_children.len());

        let mut ast = ast.with_children(new_children.clone().into());

        prop_assert_eq!(VecDeque::<Stmt>::from(new_children),ast.children());

        ast = ast.with_children(original_children.clone());
        prop_assert_eq!(original_children,ast.children());

    }

    }
}