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}