in lain_derive/src/fuzzerobject.rs [191:287]
fn gen_struct_mutate_impl(fields: &[FuzzerObjectStructField]) -> TokenStream {
let mutation_parts: Vec<TokenStream> = fields
.iter()
.map(|f| {
let mut field_mutation_tokens = TokenStream::new();
let span = f.field.span();
let ty = &f.field.ty;
let ident = &f.field.ident;
let ident_str = ident.as_ref().unwrap().to_string();
let weighted = &f.weighted;
let default_constraints = if f.min.is_some() || f.max.is_some() {
let min = f
.min
.as_ref()
.map(|v| quote! {Some(#v)})
.unwrap_or_else(|| quote! {None});
let max = f
.max
.as_ref()
.map(|v| quote! {Some(#v)})
.unwrap_or_else(|| quote! {None});
quote_spanned! { span =>
let mut constraints = Constraints::new();
constraints.min = #min;
constraints.max = #max;
constraints.max_size = max_size.clone();
constraints.weighted = #weighted;
constraints.base_object_size_accounted_for = true;
let constraints = Some(constraints);
}
} else {
quote_spanned! { span =>
let constraints = max_size.and_then(|max|{
let mut c = ::lain::types::Constraints::new();
c.base_object_size_accounted_for = true;
c.max_size(max);
Some(c)
});
}
};
field_mutation_tokens.extend(quote! {
#default_constraints
// 25% chance that this field does not get mutated
if mutator.gen_chance(0.75) {
<#ty>::mutate(&mut self.#ident, mutator, constraints.as_ref());
if <#ty>::is_variable_size() {
max_size = max_size.map(|max| {
// in case a user didn't appropriately supply a max size constraint (i.e. a max
// size that's smaller than the object's min size), we don't want to panic
let serialized_size = self.#ident.serialized_size();
if serialized_size > max {
warn!("Max size provided to object is likely smaller than min object size");
0
} else {
max - serialized_size
}
});
}
}
if mutator.should_early_bail_mutation() {
if mutator.should_fixup() {
<#ty>::fixup(&mut self.#ident, mutator);
}
return;
}
});
field_mutation_tokens
})
.collect();
quote! {
// Make a copy of the constraints that will remain immutable for
// this function. Here we ensure that the base size of this object has
// been accounted for by the caller, which may be an object containing this.
let parent_constraints = parent_constraints.and_then(|c| {
let mut c = c.clone();
c.account_for_base_object_size::<Self>();
Some(c)
});
let mut max_size = parent_constraints.as_ref().and_then(|c| c.max_size);
#(#mutation_parts)*
}
}