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!(),
}
}
}