fn gen_struct_mutate_impl()

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)*
    }
}