pravega_client_macros/
lib.rs1use proc_macro2::TokenStream;
12use quote::{quote, quote_spanned};
13use syn::spanned::Spanned;
14use syn::{parse_macro_input, parse_quote, Data, DeriveInput, Fields, GenericParam, Generics};
15
16#[proc_macro_derive(Fields)]
22pub fn derive_fields(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
23 let input = parse_macro_input!(input as DeriveInput);
25
26 let name = input.ident;
28
29 let generics = add_trait_bounds(input.generics);
31 let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
32
33 let expr = key_value_pairs(&input.data);
35 let expanded = quote! {
36 impl #impl_generics pravega_client::index::Fields for #name #ty_generics #where_clause {
38 fn get_field_values(&self) -> Vec<(&'static str, u64)> {
39 vec!{#expr}
40 }
41 }
42 };
43
44 proc_macro::TokenStream::from(expanded)
46}
47
48fn add_trait_bounds(mut generics: Generics) -> Generics {
50 for param in &mut generics.params {
51 if let GenericParam::Type(ref mut type_param) = *param {
52 type_param.bounds.push(parse_quote!(Fields));
53 }
54 }
55 generics
56}
57
58fn key_value_pairs(data: &Data) -> TokenStream {
59 match *data {
60 Data::Struct(ref data) => match data.fields {
61 Fields::Named(ref fields) => fields
62 .named
63 .iter()
64 .map(|f| {
65 let name = f.ident.as_ref().unwrap();
66 let name_str = format!("{}", name);
67
68 quote_spanned! {f.span()=>
69 (#name_str, pravega_client::index::Value::value(&self.#name)),
70 }
71 })
72 .collect(),
73 Fields::Unnamed(ref _fields) => {
74 quote! {
75 compile_error!("expected named fields");
76 }
77 }
78 Fields::Unit => {
79 quote! {
80 compile_error!("expected named fields");
81 }
82 }
83 },
84 Data::Enum(_) | Data::Union(_) => unimplemented!(),
85 }
86}