Add default attribute to TestRandom derive.
				
					
				
			Allows for generating the item from default instead of randomizing it.
This commit is contained in:
		
							parent
							
								
									f739bb5551
								
							
						
					
					
						commit
						01bfd38637
					
				@ -4,7 +4,20 @@ use crate::proc_macro::TokenStream;
 | 
			
		||||
use quote::quote;
 | 
			
		||||
use syn::{parse_macro_input, DeriveInput};
 | 
			
		||||
 | 
			
		||||
#[proc_macro_derive(TestRandom)]
 | 
			
		||||
/// Returns true if some field has an attribute declaring it should be generated from default (not
 | 
			
		||||
/// randomized).
 | 
			
		||||
///
 | 
			
		||||
/// The field attribute is: `#[test_random(default)]`
 | 
			
		||||
fn should_use_default(field: &syn::Field) -> bool {
 | 
			
		||||
    for attr in &field.attrs {
 | 
			
		||||
        if attr.tts.to_string() == "( default )" {
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[proc_macro_derive(TestRandom, attributes(test_random))]
 | 
			
		||||
pub fn test_random_derive(input: TokenStream) -> TokenStream {
 | 
			
		||||
    let derived_input = parse_macro_input!(input as DeriveInput);
 | 
			
		||||
    let name = &derived_input.ident;
 | 
			
		||||
@ -14,14 +27,32 @@ pub fn test_random_derive(input: TokenStream) -> TokenStream {
 | 
			
		||||
        _ => panic!("test_random_derive only supports structs."),
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    let field_names = get_named_field_idents(&struct_data);
 | 
			
		||||
    // Build quotes for fields that should be generated and those that should be built from
 | 
			
		||||
    // `Default`.
 | 
			
		||||
    let mut quotes = vec![];
 | 
			
		||||
    for field in &struct_data.fields {
 | 
			
		||||
        match &field.ident {
 | 
			
		||||
            Some(ref ident) => {
 | 
			
		||||
                if should_use_default(field) {
 | 
			
		||||
                    quotes.push(quote! {
 | 
			
		||||
                        #ident: <_>::default(),
 | 
			
		||||
                    });
 | 
			
		||||
                } else {
 | 
			
		||||
                    quotes.push(quote! {
 | 
			
		||||
                        #ident: <_>::random_for_test(rng),
 | 
			
		||||
                    });
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            _ => panic!("test_random_derive only supports named struct fields."),
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    let output = quote! {
 | 
			
		||||
        impl<T: RngCore> TestRandom<T> for #name {
 | 
			
		||||
            fn random_for_test(rng: &mut T) -> Self {
 | 
			
		||||
               Self {
 | 
			
		||||
                    #(
 | 
			
		||||
                        #field_names: <_>::random_for_test(rng),
 | 
			
		||||
                        #quotes
 | 
			
		||||
                    )*
 | 
			
		||||
               }
 | 
			
		||||
            }
 | 
			
		||||
@ -30,14 +61,3 @@ pub fn test_random_derive(input: TokenStream) -> TokenStream {
 | 
			
		||||
 | 
			
		||||
    output.into()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn get_named_field_idents(struct_data: &syn::DataStruct) -> Vec<(&syn::Ident)> {
 | 
			
		||||
    struct_data
 | 
			
		||||
        .fields
 | 
			
		||||
        .iter()
 | 
			
		||||
        .map(|f| match &f.ident {
 | 
			
		||||
            Some(ref ident) => ident,
 | 
			
		||||
            _ => panic!("test_random_derive only supports named struct fields."),
 | 
			
		||||
        })
 | 
			
		||||
        .collect()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user