test_strategy/
arbitrary.rs

1use crate::syn_utils::{
2    impl_trait_result, parse_parenthesized_args, to_valid_ident, Arg, Args, FieldKey,
3    GenericParamSet, SharpVals,
4};
5use crate::{bound::*, syn_utils::parse_from_attrs};
6use proc_macro2::{Span, TokenStream};
7use quote::{quote, quote_spanned, ToTokens};
8use std::{collections::HashMap, fmt::Write, mem::take};
9use structmeta::*;
10use syn::{
11    parse2, parse_quote, parse_str, spanned::Spanned, Attribute, Data, DataEnum, DataStruct,
12    DeriveInput, Expr, Fields, Ident, Index, Lit, Member, Path, Result, Type,
13};
14
15pub fn derive_arbitrary(input: DeriveInput) -> Result<TokenStream> {
16    let args: ArbitraryArgsForType = parse_from_attrs(&input.attrs, "arbitrary")?;
17    let type_parameters = if let Some(ty) = &args.args {
18        quote_spanned!(ty.span()=> type Parameters = #ty;)
19    } else {
20        quote! {
21            type Parameters = ();
22        }
23    };
24    let mut bounds = Bounds::from_data(args.bound);
25    let expr = match &input.data {
26        Data::Struct(data) => expr_for_struct(&input, data, &mut bounds)?,
27        Data::Enum(data) => expr_for_enum(&input, data, &mut bounds)?,
28        _ => bail!(
29            input.span(),
30            "`#[derive(Arbitrary)]` supports only enum and struct."
31        ),
32    };
33    impl_trait_result(
34        &input,
35        &parse_quote!(proptest::arbitrary::Arbitrary),
36        &bounds.build_wheres(quote!(proptest::arbitrary::Arbitrary + 'static)),
37        quote! {
38            #type_parameters
39            type Strategy = proptest::strategy::BoxedStrategy<Self>;
40            fn arbitrary_with(args: <Self as proptest::arbitrary::Arbitrary>::Parameters) -> Self::Strategy {
41                #[allow(dead_code)]
42                fn _to_fn_ptr<T>(f: fn(&T) -> bool) -> fn(&T) -> bool {
43                    f
44                }
45                let args = std::rc::Rc::new(args);
46                proptest::strategy::Strategy::boxed(#expr)
47            }
48        },
49        args.dump.value(),
50    )
51}
52fn expr_for_struct(
53    input: &DeriveInput,
54    data: &DataStruct,
55    bounds: &mut Bounds,
56) -> Result<TokenStream> {
57    let generics = GenericParamSet::new(&input.generics);
58    expr_for_fields(
59        parse_quote!(Self),
60        &generics,
61        &data.fields,
62        &input.attrs,
63        true,
64        bounds,
65    )
66}
67fn expr_for_enum(input: &DeriveInput, data: &DataEnum, bounds: &mut Bounds) -> Result<TokenStream> {
68    if data.variants.is_empty() {
69        bail!(Span::call_site(), "zero variant enum was not supported.");
70    }
71    let generics = GenericParamSet::new(&input.generics);
72    let mut exprs = Vec::new();
73    for variant in &data.variants {
74        let args: ArbitraryArgsForFieldOrVariant = parse_from_attrs(&variant.attrs, "arbitrary")?;
75        let mut weight = None;
76        for attr in &variant.attrs {
77            if attr.path.is_ident("weight") {
78                if weight.is_some() {
79                    bail!(attr.span(), "`#[weight]` can specify only once.");
80                }
81                weight = Some(attr.parse_args::<WeightArg>()?);
82            }
83        }
84        let weight = if let Some(arg) = weight {
85            if arg.is_zero() {
86                continue;
87            } else {
88                let expr = arg.0;
89                quote_spanned!(expr.span()=>  _to_weight(#expr))
90            }
91        } else {
92            quote!(1)
93        };
94        let variant_ident = &variant.ident;
95        let mut bounds = bounds.child(args.bound);
96        let expr = expr_for_fields(
97            parse_quote!(Self::#variant_ident),
98            &generics,
99            &variant.fields,
100            &variant.attrs,
101            false,
102            &mut bounds,
103        )?;
104        exprs.push(quote! {#weight=> #expr});
105    }
106    let s: Ident = parse_quote!(_s);
107    let filter_lets = Filter::from_enum_attrs_make_let(&input.attrs, &s)?;
108    Ok(quote! {
109        {
110            #[allow(dead_code)]
111            fn _to_weight(weight: u32) -> u32 { weight }
112            let #s = proptest::prop_oneof![#(#exprs,)*];
113            #filter_lets
114            #s
115        }
116    })
117}
118fn expr_for_fields(
119    self_path: Path,
120    generics: &GenericParamSet,
121    fields: &Fields,
122    attrs: &[Attribute],
123    filter_allow_fn: bool,
124    bounds: &mut Bounds,
125) -> Result<TokenStream> {
126    let b = StrategyBuilder::from_fields(self_path, fields, attrs, filter_allow_fn)?;
127    b.get_bound_types(generics, bounds)?;
128    b.build()
129}
130
131#[derive(StructMeta)]
132struct WeightArg(Expr);
133impl WeightArg {
134    fn is_zero(&self) -> bool {
135        if let Expr::Lit(lit) = &self.0 {
136            if let Lit::Int(lit) = &lit.lit {
137                if let Ok(value) = lit.base10_parse::<u32>() {
138                    return value == 0;
139                }
140            }
141        }
142        false
143    }
144}
145
146#[derive(StructMeta)]
147struct AnyArgs {
148    #[struct_meta(unnamed)]
149    initializer: Option<Expr>,
150    setters: HashMap<String, NameValue<Expr>>,
151}
152impl AnyArgs {
153    fn empty() -> Self {
154        Self {
155            initializer: None,
156            setters: HashMap::new(),
157        }
158    }
159    fn into_strategy(self, ty: &Type) -> TokenStream {
160        if self.initializer.is_none() && self.setters.is_empty() {
161            quote!(proptest::arbitrary::any::<#ty>())
162        } else {
163            let init = self
164                .initializer
165                .unwrap_or_else(|| parse_quote!(std::default::Default::default()));
166            if self.setters.is_empty() {
167                quote!(proptest::arbitrary::any_with::<#ty>(#init))
168            } else {
169                let mut setters: Vec<_> = self.setters.into_iter().collect();
170                setters.sort_by(|v0, v1| v0.0.cmp(&v1.0));
171                let setters = setters.into_iter().map(|(name, expr)| {
172                    let member = Member::Named(to_valid_ident(&name).unwrap());
173                    let expr = &expr.value;
174                    quote!(_any_args.#member = #expr;)
175                });
176                quote! {
177                    {
178                        let mut _any_args : <#ty as proptest::arbitrary::Arbitrary>::Parameters = #init;
179                        #(#setters)*
180                        proptest::arbitrary::any_with::<#ty>(_any_args)
181                    }
182                }
183            }
184        }
185    }
186}
187
188#[derive(StructMeta, Default)]
189struct ArbitraryArgsForType {
190    args: Option<Type>,
191    bound: Option<Vec<Bound>>,
192    dump: Flag,
193}
194
195#[derive(StructMeta, Default)]
196struct ArbitraryArgsForFieldOrVariant {
197    bound: Option<Vec<Bound>>,
198}
199
200struct Filter {
201    whence: Expr,
202    fun: Expr,
203}
204impl Filter {
205    fn parse(span: Span, args: Args) -> Result<Self> {
206        let mut values = Vec::new();
207        for arg in args {
208            match arg {
209                Arg::Value(value) => {
210                    values.push(value);
211                }
212                Arg::NameValue { .. } => bail!(arg.span(), "named argument was not supported."),
213            }
214        }
215        let whence;
216        let fun;
217        match values.len() {
218            1 => {
219                let mut iter = values.into_iter();
220                fun = iter.next().unwrap();
221                let whence_str = fun.to_token_stream().to_string();
222                whence = parse_quote!(#whence_str);
223            }
224            2 => {
225                let mut iter = values.into_iter();
226                whence = iter.next().unwrap();
227                fun = iter.next().unwrap();
228            }
229            _ => bail!(
230                span,
231                "expected `#[filter(whence, fun)]` or `#[filter(fun)]`."
232            ),
233        }
234        Ok(Self { whence, fun })
235    }
236    fn from_enum_attrs_make_let(attrs: &[Attribute], ident: &Ident) -> Result<TokenStream> {
237        let mut results = TokenStream::new();
238        for attr in attrs {
239            if attr.path.is_ident("filter") {
240                let mut sharp_vals = SharpVals::new(false, true);
241                let ts = sharp_vals.expand(attr.tokens.clone())?;
242                let filter = Filter::parse(attr.span(), parse2(ts)?)?;
243                let code = if sharp_vals.self_span.is_some() {
244                    filter.make_let_self(ident)
245                } else {
246                    let self_ty: Type = parse_quote!(Self);
247                    filter.make_let(&self_ty, ident)
248                };
249                results.extend(code);
250            }
251        }
252        Ok(results)
253    }
254    fn make_let(&self, ty: &Type, ident: &Ident) -> TokenStream {
255        let Self { whence, fun } = self;
256        quote_spanned! {fun.span()=>
257            let #ident = proptest::strategy::Strategy::prop_filter(#ident, #whence, _to_fn_ptr::<#ty>(#fun));
258        }
259    }
260    fn make_let_field(&self, ident: &Ident, field: &Ident, by_ref: bool) -> TokenStream {
261        let Self { whence, fun } = self;
262        let let_clone = if by_ref {
263            quote! {}
264        } else {
265            quote! { let #field = std::clone::Clone::clone(#field); }
266        };
267        quote_spanned! {fun.span()=>
268            let #ident = {
269                #[allow(dead_code)]
270                let args = std::clone::Clone::clone(&args);
271                proptest::strategy::Strategy::prop_filter(#ident, #whence, move |#field| {
272                    #[allow(unused_variables)]
273                    let args = std::ops::Deref::deref(&args);
274                    #let_clone
275                    #fun
276                })
277            };
278        }
279    }
280    fn make_let_self(&self, ident: &Ident) -> TokenStream {
281        let Self { whence, fun } = self;
282        quote_spanned! {fun.span()=>
283            let #ident = {
284                #[allow(dead_code)]
285                let args = std::clone::Clone::clone(&args);
286                proptest::strategy::Strategy::prop_filter(#ident, #whence, move |_self| {
287                    #[allow(unused_variables)]
288                    let args = std::ops::Deref::deref(&args);
289                    #fun
290                })
291            };
292        }
293    }
294}
295
296struct StrategyBuilder {
297    ts: TokenStream,
298    items: Vec<StrategyItem>,
299    self_path: Path,
300    fields: Fields,
301    filters_fields: Vec<FilterItem>,
302    filters_self: Vec<Filter>,
303    filters_fn: Vec<Filter>,
304}
305
306struct StrategyItem {
307    idx: usize,
308    key: FieldKey,
309    by_ref: bool,
310    is_any: bool,
311    strategy: Expr,
312    dependency: Vec<usize>,
313
314    group: Option<usize>,
315    group_next: Option<usize>,
316
317    offset: Option<usize>,
318    offset_next: Option<usize>,
319
320    group_items: Vec<usize>,
321    group_items_next: Vec<usize>,
322    group_dependency: Vec<usize>,
323    group_offset: Option<usize>,
324}
325
326struct FilterItem {
327    filter: Filter,
328    vals: Vec<usize>,
329}
330
331impl StrategyBuilder {
332    fn from_fields(
333        self_path: Path,
334        fields: &Fields,
335        attrs: &[Attribute],
336        filter_allow_self: bool,
337    ) -> Result<Self> {
338        let ts = TokenStream::new();
339        let mut key_to_idx = HashMap::new();
340        for (idx, field) in fields.iter().enumerate() {
341            key_to_idx.insert(FieldKey::from_field(idx, field), idx);
342        }
343        let mut items = Vec::new();
344        let mut filters_fields = Vec::new();
345        for (idx, field) in fields.iter().enumerate() {
346            let key = FieldKey::from_field(idx, field);
347            let func_ident = format!("_strategy_of_{}", key);
348            let mut strategy = None;
349            let mut filters_fn = Vec::new();
350            let mut filters_field = Vec::new();
351            let mut sharp_vals = SharpVals::new(true, false);
352            let mut by_ref = false;
353            let mut is_any = false;
354            for attr in &field.attrs {
355                let is_strategy_attr = attr.path.is_ident("strategy");
356                let is_any_attr = attr.path.is_ident("any");
357                if strategy.is_some() && (is_strategy_attr || is_any_attr) {
358                    bail!(
359                        attr.span(),
360                        "`#[any]` and `#[strategy]` can only be specified once in total."
361                    );
362                }
363                if is_strategy_attr {
364                    let ts = sharp_vals.expand(attr.tokens.clone())?;
365                    let args = parse_parenthesized_args(ts)?;
366                    let value = args.expect_single_value(attr.span())?;
367                    let func_ident = Ident::new(&func_ident, value.span());
368                    let ty = &field.ty;
369                    strategy = Some(quote_spanned!(value.span()=> #func_ident::<#ty, _>(#value)));
370                }
371                if is_any_attr {
372                    is_any = true;
373                    let any_attr: AnyArgs = if attr.tokens.is_empty() {
374                        AnyArgs::empty()
375                    } else {
376                        let ts: TokenStream = attr.parse_args()?;
377                        let ts = sharp_vals.expand(ts)?;
378                        parse2(ts)?
379                    };
380                    strategy = Some(any_attr.into_strategy(&field.ty));
381                }
382                if attr.path.is_ident("by_ref") {
383                    if !attr.tokens.is_empty() {
384                        bail!(
385                            attr.tokens.span(),
386                            "Brackets and arguments are not allowed."
387                        );
388                    }
389                    by_ref = true;
390                }
391                if attr.path.is_ident("filter") {
392                    let mut sharp_vals = SharpVals::new(true, false);
393                    let ts = sharp_vals.expand(attr.tokens.clone())?;
394                    let filter = Filter::parse(attr.span(), parse_parenthesized_args(ts)?)?;
395                    if sharp_vals.vals.is_empty() {
396                        filters_fn.push(filter);
397                    } else if sharp_vals.vals.contains_key(&key) {
398                        if sharp_vals.vals.len() == 1 {
399                            filters_field.push(filter);
400                        } else {
401                            let vals = to_idxs(&sharp_vals.vals, &key_to_idx)?;
402                            filters_fields.push(FilterItem { filter, vals });
403                        }
404                    } else {
405                        bail!(attr.span(), "`#{}` is not used.", key);
406                    }
407                }
408            }
409            let s: Ident = parse_quote! { _s };
410            let ty = &field.ty;
411            let strategy = if let Some(strategy) = strategy {
412                strategy
413            } else {
414                is_any = true;
415                AnyArgs::empty().into_strategy(ty)
416            };
417            let mut filter_lets = Vec::new();
418            for filter in filters_field {
419                filter_lets.push(filter.make_let_field(&s, &key.to_dummy_ident(), by_ref));
420            }
421            for filter in filters_fn {
422                filter_lets.push(filter.make_let(ty, &s));
423            }
424            let func_ident = Ident::new(&func_ident, Span::call_site());
425            let func = quote_spanned! {ty.span()=>
426                #[allow(dead_code)]
427                fn #func_ident<T: std::fmt::Debug, S: proptest::strategy::Strategy<Value = T>>(s: S) -> impl proptest::strategy::Strategy<Value = T> { s }
428            };
429            let strategy = parse_quote! {
430                {
431                    #func
432                    let #s = #strategy;
433                    #(#filter_lets)*
434                    #s
435                }
436            };
437            let dependency = to_idxs(&sharp_vals.vals, &key_to_idx)?;
438            items.push(StrategyItem::new(
439                idx, key, by_ref, is_any, strategy, dependency,
440            ));
441        }
442        let mut filters_fn = Vec::new();
443        let mut filters_self = Vec::new();
444        for attr in attrs {
445            if attr.path.is_ident("filter") {
446                let mut sharp_vals = SharpVals::new(true, filter_allow_self);
447                let ts = sharp_vals.expand(attr.tokens.clone())?;
448                let filter = Filter::parse(attr.span(), parse2(ts)?)?;
449                if !sharp_vals.vals.is_empty() {
450                    let vals = to_idxs(&sharp_vals.vals, &key_to_idx)?;
451                    filters_fields.push(FilterItem { filter, vals });
452                } else if sharp_vals.self_span.is_some() {
453                    filters_self.push(filter);
454                } else {
455                    filters_fn.push(filter);
456                }
457            }
458        }
459        let fields = fields.clone();
460        Ok(Self {
461            ts,
462            items,
463            self_path,
464            fields,
465            filters_fields,
466            filters_self,
467            filters_fn,
468        })
469    }
470    fn get_bound_types(&self, generics: &GenericParamSet, bounds: &mut Bounds) -> Result<()> {
471        if !bounds.can_extend {
472            return Ok(());
473        }
474        for (idx, field) in self.fields.iter().enumerate() {
475            let args: ArbitraryArgsForFieldOrVariant = parse_from_attrs(&field.attrs, "arbitrary")?;
476            let mut bounds = bounds.child(args.bound);
477            if bounds.can_extend && self.items[idx].is_any {
478                let ty = &field.ty;
479                if generics.contains_in_type(ty) {
480                    bounds.ty.push(ty.clone());
481                }
482            }
483        }
484        Ok(())
485    }
486    fn build(mut self) -> Result<TokenStream> {
487        if self.items.is_empty() {
488            let constructor = build_constructor(&self.self_path, &self.fields, quote!());
489            return Ok(quote! { proptest::strategy::LazyJust::new(|| #constructor ) });
490        }
491        for item in &mut self.items {
492            item.try_create_independent_strategy(&mut self.ts);
493        }
494        while !self.is_exists_all() {
495            if !self.try_create_dependent_strategy() {
496                let mut cd_str = String::new();
497                let cd_idxs = self.get_cyclic_dependency().unwrap();
498                for &cd_idx in &cd_idxs {
499                    write!(&mut cd_str, "{} -> ", &self.items[cd_idx].key).unwrap();
500                }
501                write!(&mut cd_str, "{}", &self.items[cd_idxs[0]].key).unwrap();
502                bail!(Span::call_site(), "found cyclic dependency. ({0})", cd_str);
503            }
504        }
505        self.merge_all_groups();
506        let s = &self.items[0].strategy_ident();
507        for filter in &self.filters_fields {
508            let Filter { whence, fun } = &filter.filter;
509            let mut lets = Vec::new();
510            for &field in &filter.vals {
511                lets.push(self.items[field].let_sharp_val());
512            }
513            lets.push(quote!(let args = std::clone::Clone::clone(&args);));
514            self.ts.extend(quote! {
515                let #s = {
516                    #[allow(dead_code)]
517                    let args = std::clone::Clone::clone(&args);
518                    proptest::strategy::Strategy::prop_filter(#s, #whence, move |_values| {
519                        let args = std::ops::Deref::deref(&args);
520                        #(#lets)*
521                        #fun
522                    })
523                };
524            });
525        }
526
527        let mut args = Vec::new();
528        for idx in 0..self.items.len() {
529            let key = self.items[idx]
530                .key
531                .to_valid_ident()
532                .map(|ident| quote!(#ident :));
533            let value = self.items[idx].expr();
534            args.push(quote!(#key #value))
535        }
536        let constructor = build_constructor(&self.self_path, &self.fields, quote!(#(#args, )*));
537        self.ts.extend(quote! {
538            let #s = proptest::strategy::Strategy::prop_map(#s, |_values| #constructor);
539        });
540        for filter in &self.filters_self {
541            self.ts.extend(filter.make_let_self(s));
542        }
543        let ty = parse_quote!(Self);
544        for filter in &self.filters_fn {
545            self.ts.extend(filter.make_let(&ty, s));
546        }
547        self.ts.extend(quote!(#s));
548        let ts = self.ts;
549        Ok(quote! { { #ts } })
550    }
551    fn try_create_dependent_strategy(&mut self) -> bool {
552        let mut created = false;
553        for idx in 0..self.items.len() {
554            if self.is_exists(idx) {
555                continue;
556            }
557            let group_next = self.items[idx]
558                .dependency
559                .iter()
560                .map(|&idx| self.resolve_group_next_input(idx))
561                .min()
562                .unwrap_or(None);
563            if let Some(group_next) = group_next {
564                self.set_group_next(idx, group_next);
565                for i in 0..self.items[idx].dependency.len() {
566                    self.set_group_next(self.items[idx].dependency[i], group_next)
567                }
568                created = true;
569            }
570        }
571        for idx in 0..self.items.len() {
572            if let Some(group_next) = self.resolve_group_next_input(idx) {
573                self.set_group_next(idx, group_next);
574            }
575        }
576        for idx in 0..self.items.len() {
577            self.register_group_dependency(idx);
578        }
579        for idx in 0..self.items.len() {
580            if !self.is_exists(idx) {
581                self.register_group_next_items(idx);
582            }
583        }
584        for idx in 0..self.items.len() {
585            if self.is_exists(idx) {
586                self.register_group_next_items(idx);
587            }
588        }
589        for idx in 0..self.items.len() {
590            if self.is_group_next_new(idx) {
591                let mut inputs = Vec::new();
592                let mut exprs = Vec::new();
593                for &input_idx in &self.items[idx].group_dependency {
594                    inputs.push(self.items[input_idx].strategy_ident());
595                }
596                for &group_item_next in &self.items[idx].group_items_next {
597                    exprs.push(self.strategy_expr(group_item_next));
598                }
599                let ident = self.items[idx].strategy_ident();
600                self.ts.extend(quote! {
601                    let #ident = {
602                        #[allow(dead_code)]
603                        let args = std::clone::Clone::clone(&args);
604                        proptest::strategy::Strategy::prop_flat_map((#(#inputs, )*), move |_values| (#(#exprs,)*))
605                    };
606                });
607            }
608        }
609        for idx in 0..self.items.len() {
610            self.items[idx].group = self.items[idx].group_next;
611            self.items[idx].offset = self.items[idx].offset_next.take();
612            self.items[idx].group_offset = None;
613            self.items[idx].group_items = take(&mut self.items[idx].group_items_next);
614            self.items[idx].group_dependency.clear();
615        }
616        created
617    }
618    fn resolve_group_next_input(&self, idx: usize) -> Option<usize> {
619        let item_ref = &self.items[idx];
620        item_ref.group?;
621        let group_next = item_ref.group_next?;
622        if group_next == idx {
623            return Some(idx);
624        }
625        self.resolve_group_next_input(group_next)
626    }
627    fn set_group_next(&mut self, group: usize, group_next: usize) {
628        let group_next_old = self.items[group].group_next;
629        if group_next_old == Some(group_next) {
630            return;
631        }
632        if let Some(group_next_old) = group_next_old {
633            if group_next_old != group {
634                self.set_group_next(group_next_old, group_next)
635            }
636        }
637        self.items[group].group_next = Some(group_next);
638    }
639    fn merge_all_groups(&mut self) {
640        for idx in 0..self.items.len() {
641            self.items[idx].group_next = Some(0);
642        }
643        self.merge_groups();
644    }
645    fn merge_groups(&mut self) {
646        for idx in 0..self.items.len() {
647            self.items[idx].group_next = Some(0);
648        }
649        for idx in 0..self.items.len() {
650            self.register_group_dependency(idx);
651            self.register_group_next_items(idx);
652        }
653        for idx in 0..self.items.len() {
654            if self.is_group_next_new(idx) {
655                let mut inputs = Vec::new();
656                let mut exprs = Vec::new();
657                for &input_idx in &self.items[idx].group_dependency {
658                    inputs.push(self.items[input_idx].strategy_ident());
659                }
660                for &group_item_next in &self.items[idx].group_items_next {
661                    let member = self.member(group_item_next);
662                    exprs.push(quote!(_values.#member));
663                }
664                let ident = self.items[idx].strategy_ident();
665                self.ts.extend( quote! {
666                    let #ident = proptest::strategy::Strategy::prop_map((#(#inputs, )*), |_values| (#(#exprs,)*));
667                });
668            }
669        }
670        for idx in 0..self.items.len() {
671            self.items[idx].group = self.items[idx].group_next;
672            self.items[idx].offset = self.items[idx].offset_next.take();
673            self.items[idx].group_offset = None;
674            self.items[idx].group_items = take(&mut self.items[idx].group_items_next);
675            self.items[idx].group_dependency.clear();
676        }
677    }
678    fn register_group_dependency(&mut self, idx: usize) {
679        if let Some(group_next) = self.items[idx].group_next {
680            if self.is_group(idx) {
681                self.items[idx].group_offset = Some(self.items[group_next].group_dependency.len());
682                self.items[group_next].group_dependency.push(idx);
683            }
684        }
685    }
686    fn register_group_next_items(&mut self, idx: usize) {
687        if let Some(group_next) = self.items[idx].group_next {
688            debug_assert!(self.items[idx].offset_next.is_none());
689            self.items[idx].offset_next = Some(self.items[group_next].group_items_next.len());
690            self.items[group_next].group_items_next.push(idx);
691        }
692    }
693    fn strategy_expr(&self, idx: usize) -> TokenStream {
694        if self.is_exists(idx) {
695            let member = self.member(idx);
696            quote!(proptest::strategy::Just(_values.#member))
697        } else {
698            let item_ref = &self.items[idx];
699            let mut lets = Vec::new();
700            for &dep in &item_ref.dependency {
701                let member = self.member(dep);
702                let dep = &self.items[dep];
703                let ident = &dep.key.to_dummy_ident();
704                let expr = if dep.by_ref {
705                    quote!(&_values.#member)
706                } else {
707                    quote!(std::clone::Clone::clone(&_values.#member))
708                };
709                lets.push(quote!(let #ident = #expr; ))
710            }
711            lets.push(quote! {
712                #[allow(dead_code)]
713                let args = std::ops::Deref::deref(&args);
714            });
715            let expr = &item_ref.strategy;
716            quote! {
717                {
718                    #(#lets)*
719                    #expr
720                }
721            }
722        }
723    }
724    fn get_cyclic_dependency(&self) -> Option<Vec<usize>> {
725        let mut results = Vec::new();
726        let mut to_offset = HashMap::new();
727        if self.get_cyclic_dependency_impl(0, &mut results, &mut to_offset) {
728            Some(results)
729        } else {
730            None
731        }
732    }
733    fn get_cyclic_dependency_impl(
734        &self,
735        idx: usize,
736        results: &mut Vec<usize>,
737        to_offset: &mut HashMap<usize, usize>,
738    ) -> bool {
739        if let Some(&offset) = to_offset.get(&idx) {
740            results.drain(0..offset);
741            return true;
742        }
743
744        to_offset.insert(idx, results.len());
745        results.push(idx);
746        for &dep in &self.items[idx].dependency {
747            if self.get_cyclic_dependency_impl(dep, results, to_offset) {
748                return true;
749            }
750        }
751        results.pop();
752        to_offset.remove(&idx);
753        false
754    }
755
756    fn is_exists_all(&self) -> bool {
757        (0..self.items.len()).all(|idx| self.is_exists(idx))
758    }
759    fn is_exists(&self, idx: usize) -> bool {
760        self.items[idx].group.is_some()
761    }
762    fn is_group(&self, idx: usize) -> bool {
763        self.items[idx].group == Some(idx)
764    }
765    fn is_group_next_new(&self, idx: usize) -> bool {
766        let item = &self.items[idx];
767        item.group_next == Some(idx) && item.group_items_next != item.group_items
768    }
769    fn member(&self, idx: usize) -> TokenStream {
770        let item_ref = &self.items[idx];
771        let member0 = idx_to_member(self.items[item_ref.group.unwrap()].group_offset.unwrap());
772        let member1 = idx_to_member(item_ref.offset.unwrap());
773        quote!(#member0.#member1)
774    }
775}
776
777impl StrategyItem {
778    fn new(
779        idx: usize,
780        key: FieldKey,
781        by_ref: bool,
782        is_any: bool,
783        strategy: Expr,
784        dependency: Vec<usize>,
785    ) -> Self {
786        Self {
787            idx,
788            key,
789            by_ref,
790            is_any,
791            strategy,
792            dependency,
793            group: None,
794            group_next: None,
795            offset: None,
796            offset_next: None,
797            group_items: Vec::new(),
798            group_items_next: Vec::new(),
799            group_dependency: Vec::new(),
800            group_offset: None,
801        }
802    }
803    fn try_create_independent_strategy(&mut self, ts: &mut TokenStream) -> bool {
804        if self.group.is_none() && self.dependency.is_empty() {
805            let ident = self.strategy_ident();
806            let expr = &self.strategy;
807            ts.extend(quote!(let #ident = (#expr,);));
808            self.group = Some(self.idx);
809            self.group_next = self.group;
810            self.offset = Some(0);
811            self.offset_next = None;
812            self.group_items.push(self.idx);
813            true
814        } else {
815            false
816        }
817    }
818    fn strategy_ident(&self) -> Ident {
819        parse_str(&format!("strategy_{}", self.idx)).unwrap()
820    }
821
822    fn expr(&self) -> TokenStream {
823        let member = idx_to_member(self.offset.unwrap());
824        quote!(_values.#member)
825    }
826    fn let_sharp_val(&self) -> TokenStream {
827        let expr = self.expr();
828        let expr = if self.by_ref {
829            quote!(&#expr)
830        } else {
831            quote!(std::clone::Clone::clone(&#expr))
832        };
833        let ident = &self.key.to_dummy_ident();
834        quote!(let #ident = #expr;)
835    }
836}
837
838fn idx_to_member(idx: usize) -> Member {
839    let index = idx as u32;
840    Member::Unnamed(Index {
841        index,
842        span: Span::call_site(),
843    })
844}
845
846fn build_constructor(path: &Path, fields: &Fields, args: TokenStream) -> TokenStream {
847    let args = match fields {
848        Fields::Named(_) => quote! { {#args} },
849        Fields::Unnamed(_) => quote! { (#args) },
850        Fields::Unit => quote! {},
851    };
852    quote!(#path #args)
853}
854
855fn to_idxs(
856    vals: &HashMap<FieldKey, Span>,
857    key_to_idx: &HashMap<FieldKey, usize>,
858) -> Result<Vec<usize>> {
859    let mut idxs = Vec::new();
860    for (key, &span) in vals {
861        if let Some(&idx) = key_to_idx.get(key) {
862            idxs.push(idx);
863        } else {
864            bail!(span, "cannot find value `#{}` in this scope.", key);
865        }
866    }
867    idxs.sort_unstable();
868    Ok(idxs)
869}