2019-02-22 11:16:11 +00:00
|
|
|
extern crate proc_macro;
|
|
|
|
|
|
|
|
use crate::proc_macro::TokenStream;
|
|
|
|
use quote::quote;
|
2019-02-22 14:54:18 +00:00
|
|
|
use syn::{parse_macro_input, DeriveInput};
|
2019-02-22 11:16:11 +00:00
|
|
|
|
|
|
|
#[proc_macro_derive(TestRandom)]
|
|
|
|
pub fn test_random_derive(input: TokenStream) -> TokenStream {
|
2019-02-22 14:54:18 +00:00
|
|
|
let ast = parse_macro_input!(input as DeriveInput);
|
|
|
|
let name = &ast.ident;
|
2019-02-22 11:16:11 +00:00
|
|
|
|
2019-02-22 14:54:18 +00:00
|
|
|
let struct_data = match &ast.data {
|
|
|
|
syn::Data::Struct(s) => s,
|
|
|
|
_ => panic!("test_random_derive only supports structs."),
|
|
|
|
};
|
|
|
|
|
|
|
|
let field_names = get_named_field_idents_and_types(&struct_data);
|
|
|
|
|
|
|
|
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)
|
|
|
|
)*
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
output.into()
|
2019-02-22 11:16:11 +00:00
|
|
|
}
|
|
|
|
|
2019-02-22 14:54:18 +00:00
|
|
|
fn get_named_field_idents_and_types(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()
|
|
|
|
}
|