fn new_fuzzed_enum()

in lain_derive/src/mutations.rs [298:357]


fn new_fuzzed_enum(variants: &[Variant], cont_ident: &syn::Ident) -> TokenStream {
    let constraints_prelude = constraints_prelude();
    let (weights, new_fuzzed_fields, ignore_chances) =
        new_fuzzed_enum_visitor(variants, cont_ident);
    let variant_count = new_fuzzed_fields.len();

    if new_fuzzed_fields.is_empty() {
        return quote! {Default::default()};
    }

    let mut match_arms = vec![];

    for (i, variant) in new_fuzzed_fields.iter().enumerate() {
        match_arms.push(quote! {
            #i => {
                #variant

                value.fixup(mutator);

                value
            }
        });
    }

    quote! {
        use _lain::rand::seq::SliceRandom;
        use _lain::rand::distributions::Distribution;

        static weights: [u64; #variant_count] = [#(#weights,)*];
        static ignore_chances: [f64; #variant_count] = [#(#ignore_chances,)*];

        _lain::lazy_static::lazy_static! {
            static ref dist: _lain::rand::distributions::WeightedIndex<u64> =
                _lain::rand::distributions::WeightedIndex::new(&weights).unwrap();
        }

        #constraints_prelude

        // compiler analysis doesn't think we loop at least once, so it thinks this
        // var is uninitialized. this is a stupid bypass
        let mut idx: Option<usize> = None;
        // loop a max of 5 times to avoid an infinite loop
        for _i in 0..5 {
            idx = Some(dist.sample(&mut mutator.rng));
            let chance = ignore_chances[idx.unwrap()];

            // negate the gen_chance call since this is a chance to *ignore*
            if chance >= 1.0 || !mutator.gen_chance(chance) {
                break;
            }
        }

        let idx = idx.unwrap();

        match idx {
            #(#match_arms)*
            _ => unreachable!(),
        }
    }
}