pbt 0.4.22

Property-based testing with `derive` macros, aware of mutual induction & instantiability.
Documentation
//! Implementation for `Option<_>`.

use {
    crate::{
        multiset::Multiset,
        pbt::{
            Algebraic, ArbitraryFn, CtorFn, Decomposition, ElimFn, IntroductionRule, Pbt,
            TypeFormer, arbitrary_field, visit_self,
        },
        reflection::{TermsOfVariousTypes, Type, register, type_of},
        scc::StronglyConnectedComponents,
    },
    alloc::collections::BTreeSet,
    core::{iter, num::NonZero},
};

impl<T: Pbt> Pbt for Option<T> {
    #[inline]
    fn register_all_immediate_dependencies(
        visited: &mut BTreeSet<Type>,
        sccs: &mut StronglyConnectedComponents,
    ) {
        if !visited.insert(type_of::<Self>()) {
            return;
        }
        let () = register::<T>(visited.clone(), sccs);
    }

    #[inline]
    fn type_former() -> TypeFormer<Self> {
        TypeFormer::Algebraic(Algebraic {
            introduction_rules: vec![
                IntroductionRule {
                    arbitrary: ArbitraryFn::new(|_, _| Ok(Some(None))),
                    call: CtorFn::new(|_| Some(None)),
                    immediate_dependencies: Multiset::new(),
                },
                IntroductionRule {
                    arbitrary: ArbitraryFn::new(|prng, mut sizes| {
                        Ok(Some(Some(arbitrary_field::<T>(&mut sizes, prng)?)))
                    }),
                    call: CtorFn::new(|terms| Some(Some(terms.must_pop()))),
                    immediate_dependencies: iter::once(type_of::<T>()).collect(),
                },
            ],
            elimination_rule: ElimFn::new(|opt| {
                let mut fields = TermsOfVariousTypes::new();
                let ctor_idx = match opt {
                    None => 1,
                    Some(t) => {
                        let () = fields.push::<T>(t);
                        2
                    }
                };
                Decomposition {
                    // SAFETY: Case analysis above.
                    ctor_idx: unsafe { NonZero::new_unchecked(ctor_idx) },
                    fields,
                }
            }),
        })
    }

    #[inline]
    fn visit_deep<V>(&self) -> impl Iterator<Item = V>
    where
        V: Pbt,
    {
        visit_self(self).chain(self.as_ref().map(T::visit_deep).into_iter().flatten())
    }
}