1 use super::generate_fields;
2 use proc_macro2::{Ident, Literal, TokenStream};
4 use syn::{DataEnum, Variant};
6 fn variant_weight(variant: &Variant) -> Literal {
7 for attr in variant.attrs.iter() {
8 if attr.path.is_ident("weight") {
10 .parse_args::<Literal>()
11 .expect("expected literal for `#[weight(...)]`");
14 Literal::u64_suffixed(1)
17 pub fn generate(name: &Ident, ty: DataEnum) -> TokenStream {
18 let variant_weights = ty
22 .map(|(i, variant)| (i, variant_weight(&variant), variant));
24 let mut arms = TokenStream::new();
25 let mut arms_variant = TokenStream::new();
26 let mut arms_variant_name = TokenStream::new();
27 let mut num_variants: usize = 0;
29 let mut total_weight = quote! { 0 };
30 for (index, weight, variant) in variant_weights {
31 let variant_name = variant.ident;
34 let end = start + #weight;
35 if start <= value && value < end {
36 return generate_random::GenerateRandomVariant::generate_random_variant(rng, #index);
40 let fields = generate_fields(variant.fields);
41 arms_variant.extend(quote! {
42 #index => Self::#variant_name #fields,
45 let variant_str = variant_name.to_string();
46 arms_variant_name.extend(quote! {
47 #index => #variant_str,
50 total_weight = quote! { #total_weight + #weight };
55 impl generate_random::GenerateRandom for #name {
56 fn generate_random<R: rand::Rng + ?Sized>(rng: &mut R) -> Self {
57 let total_weight = #total_weight;
58 let value = rng.gen_range(0..total_weight);
65 impl generate_random::GenerateRandomVariant for #name {
66 fn num_variants() -> usize {
70 fn variant_name(variant: usize) -> &'static str {
77 fn generate_random_variant<R: rand::Rng + ?Sized>(rng: &mut R, variant: usize) -> Self {
80 _ => generate_random::GenerateRandom::generate_random(rng),