Skip to main content

mutatis_derive/
lib.rs

1extern crate proc_macro;
2
3use proc_macro2::{Span, TokenStream};
4use quote::quote;
5use syn::{spanned::Spanned, *};
6
7mod container_attributes;
8mod field_attributes;
9use container_attributes::ContainerAttributes;
10use field_attributes::FieldBehavior;
11
12static MUTATIS_ATTRIBUTE_NAME: &str = "mutatis";
13
14#[proc_macro_derive(Mutate, attributes(mutatis))]
15pub fn derive_mutator(tokens: proc_macro::TokenStream) -> proc_macro::TokenStream {
16    let input = syn::parse_macro_input!(tokens as DeriveInput);
17    expand_derive_mutator(input)
18        .unwrap_or_else(syn::Error::into_compile_error)
19        .into()
20}
21
22fn expand_derive_mutator(input: DeriveInput) -> Result<TokenStream> {
23    let container_attrs = ContainerAttributes::from_derive_input(&input)?;
24    let mutator_ty = MutatorType::new(&input, &container_attrs)?;
25
26    let mutator_type_def = gen_mutator_type_def(&input, &mutator_ty, &container_attrs)?;
27    let mutator_type_default_impl = gen_mutator_type_default_impl(&mutator_ty)?;
28    let mutator_ctor = gen_mutator_ctor(&mutator_ty)?;
29    let mutator_impl = gen_mutator_impl(&input, &mutator_ty)?;
30    let default_mutator_impl = gen_default_mutator_impl(&mutator_ty, &container_attrs)?;
31
32    Ok(quote! {
33        #mutator_type_def
34        #mutator_type_default_impl
35        #mutator_ctor
36        #mutator_impl
37        #default_mutator_impl
38    })
39}
40
41struct MutatorType {
42    ty_name: Ident,
43
44    mutator_name: Ident,
45
46    mutator_fields: Vec<MutatorField>,
47
48    /// A vec of quoted generic parameters, without any bounds but with `const`
49    /// defs, e.g. `'a`, `const N: usize`, or `T`.
50    ty_impl_generics: Vec<TokenStream>,
51
52    /// A vec of quoted generic parameters, without any bounds and without any
53    /// `const` defs, e.t. `'a`, `N`, or `T.
54    ty_name_generics: Vec<TokenStream>,
55
56    /// A vec of quoted bounds for the generics above, e.g. `A: Iterator<Item =
57    /// B>,`.
58    ty_generics_bounds: Vec<TokenStream>,
59}
60
61impl MutatorType {
62    fn new(input: &DeriveInput, container_attrs: &ContainerAttributes) -> Result<Self> {
63        let ty_name = input.ident.clone();
64
65        let mutator_name = container_attrs
66            .mutator_name
67            .clone()
68            .unwrap_or_else(|| Ident::new(&format!("{}Mutator", input.ident), input.ident.span()));
69
70        let mutator_fields = get_mutator_fields(&input)?;
71
72        let mut ty_impl_generics = vec![];
73        let mut ty_name_generics = vec![];
74        let mut ty_generics_bounds = vec![];
75
76        for gen in &input.generics.params {
77            match gen {
78                GenericParam::Lifetime(l) => {
79                    if !l.bounds.is_empty() {
80                        ty_generics_bounds.push(quote! { #l });
81                    }
82
83                    let l = &l.lifetime;
84                    ty_impl_generics.push(quote! { #l });
85                    ty_name_generics.push(quote! { #l });
86                }
87                GenericParam::Const(c) => {
88                    ty_impl_generics.push(quote! { #c });
89                    let c = &c.ident;
90                    ty_name_generics.push(quote! { #c });
91                }
92                GenericParam::Type(t) => {
93                    if !t.bounds.is_empty() {
94                        ty_generics_bounds.push(quote! { #t });
95                    }
96                    let t = &t.ident;
97                    ty_impl_generics.push(quote! { #t });
98                    ty_name_generics.push(quote! { #t });
99                }
100            }
101        }
102
103        if let Some(wc) = &input.generics.where_clause {
104            for bound in wc.predicates.iter() {
105                ty_generics_bounds.push(quote! { #bound });
106            }
107        }
108
109        Ok(Self {
110            ty_name,
111            mutator_name,
112            mutator_fields,
113            ty_impl_generics,
114            ty_name_generics,
115            ty_generics_bounds,
116        })
117    }
118
119    fn mutator_impl_generics_iter(&self) -> impl Iterator<Item = TokenStream> + '_ {
120        self.ty_impl_generics.iter().cloned().chain(
121            self.mutator_fields
122                .iter()
123                .filter_map(|f| f.generic.as_ref().map(|g| quote! { #g })),
124        )
125    }
126
127    /// All the `impl` generic parameters for this mutator, including those
128    /// inherited from the type that it is a mutator for.
129    fn mutator_impl_generics(&self) -> TokenStream {
130        let impl_generics = self
131            .ty_impl_generics
132            .iter()
133            .cloned()
134            .chain(
135                self.mutator_fields
136                    .iter()
137                    .filter_map(|f| f.generic.as_ref().map(|g| quote! { #g })),
138            )
139            .collect::<Vec<_>>();
140        if impl_generics.is_empty() {
141            quote! {}
142        } else {
143            quote! { < #( #impl_generics ),* > }
144        }
145    }
146
147    /// All the named (i.e. just the "N" and excluding "const", ":", and "usize"
148    /// in `const N: usize` generics) generic parameters for this mutator,
149    /// including those inherited from the type that it is a mutator for.
150    fn mutator_name_generics_iter(&self) -> impl Iterator<Item = TokenStream> + '_ {
151        self.ty_name_generics.iter().cloned().chain(
152            self.mutator_fields
153                .iter()
154                .filter_map(|f| f.generic.as_ref().map(|g| quote! { #g })),
155        )
156    }
157
158    fn mutator_impl_generics_with_defaults_iter(&self) -> impl Iterator<Item = TokenStream> + '_ {
159        self.ty_impl_generics
160            .iter()
161            .cloned()
162            .chain(self.mutator_fields.iter().filter_map(move |f| {
163                f.generic.as_ref().map(|g| {
164                    let for_ty = &f.for_ty;
165                    quote! { #g = <#for_ty as mutatis::DefaultMutate>::DefaultMutate }
166                })
167            }))
168    }
169
170    fn ty_name_with_generics(&self) -> TokenStream {
171        let ty_name = &self.ty_name;
172        if self.ty_name_generics.is_empty() {
173            quote! { #ty_name }
174        } else {
175            let ty_generics = self.ty_name_generics.iter();
176            quote! { #ty_name < #( #ty_generics ),* > }
177        }
178    }
179
180    fn mutator_name_with_generics(&self, kind: MutatorNameGenericsKind) -> TokenStream {
181        let mutator_name = &self.mutator_name;
182
183        let generics = match kind {
184            MutatorNameGenericsKind::Generics => {
185                self.mutator_name_generics_iter().collect::<Vec<_>>()
186            }
187            MutatorNameGenericsKind::Impl {
188                impl_default: false,
189            } => self.mutator_impl_generics_iter().collect::<Vec<_>>(),
190            MutatorNameGenericsKind::Impl { impl_default: true } => self
191                .mutator_impl_generics_with_defaults_iter()
192                .collect::<Vec<_>>(),
193            MutatorNameGenericsKind::JustTyGenerics => self.ty_name_generics.clone(),
194        };
195
196        if generics.is_empty() {
197            quote! { #mutator_name }
198        } else {
199            quote! { #mutator_name < #( #generics ),* > }
200        }
201    }
202
203    fn where_clause(&self, kind: WhereClauseKind) -> TokenStream {
204        let mut bounds = self.ty_generics_bounds.clone();
205
206        match kind {
207            WhereClauseKind::NoMutateBounds => {}
208            WhereClauseKind::MutateBounds => {
209                for f in &self.mutator_fields {
210                    let for_ty = &f.for_ty;
211                    if let Some(g) = f.generic.as_ref() {
212                        bounds.push(quote! { #g: mutatis::Mutate<#for_ty> });
213                    } else {
214                        debug_assert_eq!(f.behavior, FieldBehavior::DefaultMutate);
215                        bounds.push(quote! { #for_ty: mutatis::DefaultMutate });
216                    }
217                }
218            }
219            WhereClauseKind::MutateAndGenerateBounds => {
220                for f in &self.mutator_fields {
221                    let for_ty = &f.for_ty;
222                    if let Some(g) = f.generic.as_ref() {
223                        bounds.push(
224                            quote! { #g: mutatis::Mutate<#for_ty> + mutatis::Generate<#for_ty> },
225                        );
226                    } else {
227                        debug_assert_eq!(f.behavior, FieldBehavior::DefaultMutate);
228                        bounds.push(quote! { #for_ty: mutatis::DefaultMutate });
229                        bounds.push(quote! { <#for_ty as mutatis::DefaultMutate>::DefaultMutate: mutatis::Generate<#for_ty> });
230                    }
231                }
232            }
233            WhereClauseKind::DefaultBounds => {
234                for f in &self.mutator_fields {
235                    if let Some(g) = f.generic.as_ref() {
236                        bounds.push(quote! { #g: Default });
237                    } else {
238                        let for_ty = &f.for_ty;
239                        debug_assert_eq!(f.behavior, FieldBehavior::DefaultMutate);
240                        bounds.push(quote! { #for_ty: mutatis::DefaultMutate });
241                    }
242                }
243            }
244            WhereClauseKind::DefaultMutateBounds => {
245                for f in &self.mutator_fields {
246                    let for_ty = &f.for_ty;
247                    bounds.push(quote! { #for_ty: mutatis::DefaultMutate });
248                }
249            }
250        }
251
252        if bounds.is_empty() {
253            quote! {}
254        } else {
255            quote! { where #( #bounds ),* }
256        }
257    }
258
259    fn phantom_fields_defs<'a>(
260        &self,
261        input: &'a DeriveInput,
262    ) -> impl Iterator<Item = TokenStream> + 'a {
263        let make_phantom_field = |i, ty| {
264            let ident = Ident::new(&format!("_phantom{i}"), Span::call_site());
265            quote! { #ident : core::marker::PhantomData<#ty> , }
266        };
267
268        input
269            .generics
270            .params
271            .iter()
272            .enumerate()
273            .map(move |(i, g)| match g {
274                GenericParam::Lifetime(l) => {
275                    let l = &l.lifetime;
276                    make_phantom_field(i, quote! { & #l () })
277                }
278                GenericParam::Const(c) => {
279                    let c = &c.ident;
280                    make_phantom_field(i, quote! { [(); #c] })
281                }
282                GenericParam::Type(t) => {
283                    let t = &t.ident;
284                    make_phantom_field(i, quote! { #t })
285                }
286            })
287    }
288
289    fn phantom_fields_literals(&self) -> impl Iterator<Item = TokenStream> + '_ {
290        (0..self.ty_name_generics.len()).map(|i| {
291            let ident = Ident::new(&format!("_phantom{i}"), Span::call_site());
292            quote! { #ident : core::marker::PhantomData, }
293        })
294    }
295}
296
297#[derive(Clone, Copy)]
298enum WhereClauseKind {
299    NoMutateBounds,
300    MutateBounds,
301    MutateAndGenerateBounds,
302    DefaultBounds,
303    DefaultMutateBounds,
304}
305
306#[derive(Clone, Copy)]
307enum MutatorNameGenericsKind {
308    Generics,
309    Impl { impl_default: bool },
310    JustTyGenerics,
311}
312
313struct MutatorField {
314    /// The identifier for this field inside the mutator struct.
315    ident: Ident,
316    /// The generic type parameter for this field, if any.
317    generic: Option<Ident>,
318    /// The behavior for this field.
319    behavior: FieldBehavior,
320    /// The type that this field is a mutator for.
321    for_ty: Type,
322}
323
324fn get_mutator_fields(input: &DeriveInput) -> Result<Vec<MutatorField>> {
325    let mut i = 0;
326    let mut generic = |b: &FieldBehavior| -> Option<Ident> {
327        if b.needs_generic() {
328            let g = Ident::new(&format!("MutatorT{}", i), Span::call_site());
329            i += 1;
330            Some(g)
331        } else {
332            None
333        }
334    };
335
336    match &input.data {
337        Data::Struct(data) => match &data.fields {
338            Fields::Named(fields) => fields
339                .named
340                .iter()
341                .filter_map(|f| {
342                    FieldBehavior::for_field(f)
343                        .map(|b| {
344                            b.map(|b| MutatorField {
345                                ident: f.ident.clone().unwrap(),
346                                generic: generic(&b),
347                                behavior: b,
348                                for_ty: f.ty.clone(),
349                            })
350                        })
351                        .transpose()
352                })
353                .collect(),
354            Fields::Unnamed(fields) => fields
355                .unnamed
356                .iter()
357                .enumerate()
358                .filter_map(|(i, f)| {
359                    FieldBehavior::for_field(f)
360                        .map(|b| {
361                            b.map(|b| MutatorField {
362                                ident: Ident::new(&format!("field{}", i), f.span()),
363                                generic: generic(&b),
364                                behavior: b,
365                                for_ty: f.ty.clone(),
366                            })
367                        })
368                        .transpose()
369                })
370                .collect(),
371            Fields::Unit => Ok(vec![]),
372        },
373        Data::Enum(data) => Ok(data
374            .variants
375            .iter()
376            .map(|v| {
377                let prefix = v.ident.to_string().to_lowercase();
378                match v.fields {
379                    Fields::Named(ref fields) => fields
380                        .named
381                        .iter()
382                        .filter_map(|f| {
383                            FieldBehavior::for_field(f)
384                                .map(|b| {
385                                    b.map(|b| MutatorField {
386                                        ident: Ident::new(
387                                            &format!("{prefix}_{}", f.ident.clone().unwrap()),
388                                            f.span(),
389                                        ),
390                                        generic: generic(&b),
391                                        behavior: b,
392                                        for_ty: f.ty.clone(),
393                                    })
394                                })
395                                .transpose()
396                        })
397                        .collect::<Result<Vec<_>>>(),
398                    Fields::Unnamed(ref fields) => fields
399                        .unnamed
400                        .iter()
401                        .enumerate()
402                        .filter_map(|(i, f)| {
403                            FieldBehavior::for_field(f)
404                                .map(|b| {
405                                    b.map(|b| MutatorField {
406                                        ident: Ident::new(&format!("{prefix}{i}"), f.span()),
407                                        generic: generic(&b),
408                                        behavior: b,
409                                        for_ty: f.ty.clone(),
410                                    })
411                                })
412                                .transpose()
413                        })
414                        .collect::<Result<Vec<_>>>(),
415                    Fields::Unit => Ok(vec![]),
416                }
417            })
418            .collect::<Result<Vec<_>>>()?
419            .into_iter()
420            .flat_map(|fs| fs)
421            .collect()),
422        Data::Union(_) => Err(Error::new_spanned(
423            input,
424            "cannot `derive(Mutate)` on a union",
425        )),
426    }
427}
428
429fn gen_mutator_type_def(
430    input: &DeriveInput,
431    mutator_ty: &MutatorType,
432    container_attrs: &ContainerAttributes,
433) -> Result<TokenStream> {
434    let vis = &input.vis;
435    let name = &input.ident;
436
437    let impl_default = container_attrs.default_mutate.unwrap_or(true);
438    let mutator_name =
439        mutator_ty.mutator_name_with_generics(MutatorNameGenericsKind::Impl { impl_default });
440
441    let mut temp: Option<LitStr> = None;
442    let doc = container_attrs.mutator_doc.as_deref().unwrap_or_else(|| {
443        temp = Some(LitStr::new(
444            &format!(" A mutator for the `{name}` type."),
445            input.ident.span(),
446        ));
447        std::slice::from_ref(temp.as_ref().unwrap())
448    });
449
450    let where_clause = mutator_ty.where_clause(WhereClauseKind::NoMutateBounds);
451
452    let fields = mutator_ty
453        .mutator_fields
454        .iter()
455        .map(|f| {
456            let ident = &f.ident;
457            if let Some(g) = f.generic.as_ref() {
458                quote! { #ident: #g , }
459            } else {
460                let for_ty = &f.for_ty;
461                debug_assert_eq!(f.behavior, FieldBehavior::DefaultMutate);
462                quote! { #ident: <#for_ty as mutatis::DefaultMutate>::DefaultMutate, }
463            }
464        })
465        .collect::<Vec<_>>();
466
467    let phantoms = mutator_ty.phantom_fields_defs(input);
468
469    Ok(quote! {
470        #( #[doc = #doc] )*
471        // #[derive(Clone, Debug)]
472        #vis struct #mutator_name #where_clause {
473            #( #fields )*
474            #( #phantoms )*
475            _private: (),
476        }
477    })
478}
479
480fn gen_mutator_type_default_impl(mutator_ty: &MutatorType) -> Result<TokenStream> {
481    let impl_generics = mutator_ty.mutator_impl_generics();
482    let mutator_name = mutator_ty.mutator_name_with_generics(MutatorNameGenericsKind::Generics);
483    let where_clause = mutator_ty.where_clause(WhereClauseKind::DefaultBounds);
484
485    let fields = mutator_ty
486        .mutator_fields
487        .iter()
488        .map(|f| {
489            let ident = &f.ident;
490            quote! { #ident: Default::default(), }
491        })
492        .collect::<Vec<_>>();
493
494    let phantoms = mutator_ty.phantom_fields_literals();
495
496    Ok(quote! {
497        #[automatically_derived]
498        impl #impl_generics Default for #mutator_name #where_clause {
499            fn default() -> Self {
500                Self {
501                    #( #fields )*
502                    #( #phantoms )*
503                    _private: (),
504                }
505            }
506        }
507    })
508}
509
510fn gen_mutator_ctor(mutator_ty: &MutatorType) -> Result<TokenStream> {
511    let impl_generics = mutator_ty.mutator_impl_generics();
512
513    let params = mutator_ty
514        .mutator_fields
515        .iter()
516        .filter_map(|f| {
517            f.generic.as_ref().map(|g| {
518                let ident = &f.ident;
519                quote! { #ident: #g , }
520            })
521        })
522        .collect::<Vec<_>>();
523
524    let fields = mutator_ty
525        .mutator_fields
526        .iter()
527        .map(|f| {
528            let ident = &f.ident;
529            if f.generic.is_some() {
530                quote! { #ident , }
531            } else {
532                let for_ty = &f.for_ty;
533                debug_assert_eq!(f.behavior, FieldBehavior::DefaultMutate);
534                quote! { #ident: mutatis::mutators::default::<#for_ty>() , }
535            }
536        })
537        .collect::<Vec<_>>();
538
539    let name = &mutator_ty.mutator_name_with_generics(MutatorNameGenericsKind::Generics);
540    let doc = format!("Construct a new `{name}` instance.");
541    let where_clause = mutator_ty.where_clause(WhereClauseKind::NoMutateBounds);
542    let phantoms = mutator_ty.phantom_fields_literals();
543
544    Ok(quote! {
545        impl #impl_generics #name #where_clause {
546            #[doc = #doc]
547            #[inline]
548            pub fn new( #( #params )* ) -> Self {
549                Self {
550                    #( #fields )*
551                    #( #phantoms )*
552                    _private: (),
553                }
554            }
555        }
556    })
557}
558
559fn gen_mutator_impl(input: &DeriveInput, mutator_ty: &MutatorType) -> Result<TokenStream> {
560    let impl_generics = mutator_ty.mutator_impl_generics();
561
562    let ty_name = mutator_ty.ty_name_with_generics();
563
564    let is_multi_variant_enum = matches!(&input.data, Data::Enum(data) if data.variants.len() > 1);
565    let where_clause = if is_multi_variant_enum {
566        mutator_ty.where_clause(WhereClauseKind::MutateAndGenerateBounds)
567    } else {
568        mutator_ty.where_clause(WhereClauseKind::MutateBounds)
569    };
570
571    let mut fields_iter = mutator_ty.mutator_fields.iter();
572    let mut make_mutation = |value| {
573        let ident = &fields_iter.next().unwrap().ident;
574        quote! { self.#ident.mutate(mutations, #value)?; }
575    };
576
577    let mutation_body = match &input.data {
578        Data::Struct(data) => match &data.fields {
579            Fields::Named(fields) => {
580                let mutations = fields
581                    .named
582                    .iter()
583                    .filter(|f| FieldBehavior::for_field(f).unwrap().is_some())
584                    .map(|f| {
585                        let ident = &f.ident;
586                        make_mutation(quote! { &mut value.#ident })
587                    });
588                quote! {
589                    #( #mutations )*
590                }
591            }
592            Fields::Unnamed(fields) => {
593                let mutations = fields
594                    .unnamed
595                    .iter()
596                    .enumerate()
597                    .filter(|(_i, f)| FieldBehavior::for_field(f).unwrap().is_some())
598                    .map(|(i, f)| {
599                        let index = Index {
600                            index: u32::try_from(i).unwrap(),
601                            span: f.span(),
602                        };
603                        make_mutation(quote! { &mut value.#index })
604                    });
605                quote! {
606                    #( #mutations )*
607                }
608            }
609            Fields::Unit => quote! {},
610        },
611
612        Data::Enum(data) => {
613            // Build the existing field-mutation match arms.
614            let mut field_mutation_arms = vec![];
615            for v in data.variants.iter() {
616                let variant_ident = &v.ident;
617                match &v.fields {
618                    Fields::Named(fields) => {
619                        let mut patterns = vec![];
620                        let mutates = fields
621                            .named
622                            .iter()
623                            .filter_map(|f| {
624                                let ident = &f.ident;
625                                if FieldBehavior::for_field(f).unwrap().is_some() {
626                                    patterns.push(quote! { #ident , });
627                                    Some(make_mutation(quote! { #ident }))
628                                } else {
629                                    patterns.push(quote! { #ident: _ , });
630                                    None
631                                }
632                            })
633                            .collect::<Vec<_>>();
634                        field_mutation_arms.push(quote! {
635                            #ty_name::#variant_ident { #( #patterns )* } => {
636                                #( #mutates )*
637                            }
638                        });
639                    }
640
641                    Fields::Unnamed(fields) => {
642                        let mut patterns = vec![];
643                        let mutates = fields
644                            .unnamed
645                            .iter()
646                            .enumerate()
647                            .filter_map(|(i, f)| {
648                                if FieldBehavior::for_field(f).unwrap().is_some() {
649                                    let binding = Ident::new(&format!("field{}", i), f.span());
650                                    patterns.push(quote! { #binding , });
651                                    Some(make_mutation(quote! { #binding }))
652                                } else {
653                                    patterns.push(quote! { _ , });
654                                    None
655                                }
656                            })
657                            .collect::<Vec<_>>();
658                        field_mutation_arms.push(quote! {
659                            #ty_name::#variant_ident( #( #patterns )* ) => {
660                                #( #mutates )*
661                            }
662                        });
663                    }
664
665                    Fields::Unit => {
666                        field_mutation_arms.push(quote! {
667                            #ty_name::#variant_ident => {}
668                        });
669                    }
670                }
671            }
672
673            // Build variant-switching mutations for enums with multiple
674            // variants.
675            let variant_switching = if data.variants.len() > 1 {
676                // Build a match to determine the current variant index.
677                let index_arms: Vec<_> = data
678                    .variants
679                    .iter()
680                    .enumerate()
681                    .map(|(v_idx, v)| {
682                        let variant_ident = &v.ident;
683                        match &v.fields {
684                            Fields::Named(_) => {
685                                quote! { #ty_name::#variant_ident { .. } => #v_idx, }
686                            }
687                            Fields::Unnamed(_) => {
688                                quote! { #ty_name::#variant_ident(..) => #v_idx, }
689                            }
690                            Fields::Unit => quote! { #ty_name::#variant_ident => #v_idx, },
691                        }
692                    })
693                    .collect();
694
695                // For each variant, build an expression that constructs a new
696                // instance of that variant. For non-ignored fields, use the
697                // mutator's `generate` method. For ignored fields, use
698                // `Default::default()`.
699                let mut variant_mutations = vec![];
700                let mut mutator_field_offset = 0usize;
701                for (v_idx, v) in data.variants.iter().enumerate() {
702                    let variant_ident = &v.ident;
703
704                    let construction = match &v.fields {
705                        Fields::Named(fields) => {
706                            let field_exprs: Vec<_> = fields
707                                .named
708                                .iter()
709                                .map(|f| {
710                                    let ident = &f.ident;
711                                    if let Some(_behavior) = FieldBehavior::for_field(f).unwrap() {
712                                        let mutator_ident =
713                                            &mutator_ty.mutator_fields[mutator_field_offset].ident;
714                                        mutator_field_offset += 1;
715                                        quote! { #ident: self.#mutator_ident.generate(ctx)? }
716                                    } else {
717                                        quote! { #ident: Default::default() }
718                                    }
719                                })
720                                .collect();
721                            quote! {
722                                *value = #ty_name::#variant_ident { #( #field_exprs ),* };
723                            }
724                        }
725                        Fields::Unnamed(fields) => {
726                            let field_exprs: Vec<_> = fields
727                                .unnamed
728                                .iter()
729                                .map(|f| {
730                                    if let Some(_behavior) = FieldBehavior::for_field(f).unwrap() {
731                                        let mutator_ident =
732                                            &mutator_ty.mutator_fields[mutator_field_offset].ident;
733                                        mutator_field_offset += 1;
734                                        quote! { self.#mutator_ident.generate(ctx)? }
735                                    } else {
736                                        quote! { Default::default() }
737                                    }
738                                })
739                                .collect();
740                            quote! {
741                                *value = #ty_name::#variant_ident( #( #field_exprs ),* );
742                            }
743                        }
744                        Fields::Unit => {
745                            quote! {
746                                *value = #ty_name::#variant_ident;
747                            }
748                        }
749                    };
750
751                    variant_mutations.push((v_idx, construction));
752                }
753
754                let num_variants = data.variants.len();
755                let switch_stmts: Vec<_> = variant_mutations
756                    .iter()
757                    .map(|(v_idx, construction)| {
758                        quote! {
759                            if _variant_index != #v_idx {
760                                mutations.mutation(|ctx| {
761                                    #construction
762                                    Ok(())
763                                })?;
764                            }
765                        }
766                    })
767                    .collect();
768
769                quote! {
770                    let _variant_index: usize = match value {
771                        #( #index_arms )*
772                    };
773                    let _ = #num_variants;
774                    #( #switch_stmts )*
775                }
776            } else {
777                quote! {}
778            };
779
780            quote! {
781                #variant_switching
782                match value {
783                    #( #field_mutation_arms )*
784                }
785            }
786        }
787
788        Data::Union(_) => {
789            return Err(Error::new_spanned(
790                input,
791                "cannot `derive(Mutate)` on a union",
792            ))
793        }
794    };
795
796    let mutate_method = quote! {
797        fn mutate(
798            &mut self,
799            mutations: &mut mutatis::Candidates,
800            value: &mut #ty_name,
801        ) -> mutatis::Result<()> {
802            #mutation_body
803
804            // Silence unused-variable warnings if every field was marked `ignore`.
805            let _ = (mutations, value);
806
807            Ok(())
808        }
809    };
810
811    let mutator_name = &mutator_ty.mutator_name_with_generics(MutatorNameGenericsKind::Generics);
812
813    Ok(quote! {
814        #[automatically_derived]
815        impl #impl_generics mutatis::Mutate<#ty_name> for #mutator_name
816            #where_clause
817        {
818            #mutate_method
819        }
820    })
821}
822
823fn gen_default_mutator_impl(
824    mutator_ty: &MutatorType,
825    container_attrs: &ContainerAttributes,
826) -> Result<TokenStream> {
827    let impl_default = container_attrs.default_mutate.unwrap_or(true);
828    if !impl_default {
829        return Ok(quote! {});
830    }
831
832    let ty_generics = if mutator_ty.ty_impl_generics.is_empty() {
833        quote! {}
834    } else {
835        let gens = &mutator_ty.ty_impl_generics;
836        quote! { < #( #gens ),* > }
837    };
838
839    let ty_name = mutator_ty.ty_name_with_generics();
840    let where_clause = mutator_ty.where_clause(WhereClauseKind::DefaultMutateBounds);
841    let mutator_name =
842        &mutator_ty.mutator_name_with_generics(MutatorNameGenericsKind::JustTyGenerics);
843
844    Ok(quote! {
845        #[automatically_derived]
846        impl #ty_generics mutatis::DefaultMutate for #ty_name
847            #where_clause
848        {
849            type DefaultMutate = #mutator_name;
850        }
851    })
852}