use proc_macro::TokenStream;
use quote::quote;
use syn::{DeriveInput, Lit, Meta, MetaNameValue, parse_macro_input};
#[proc_macro_derive(UmiTagged, attributes(umi_tagged))]
pub fn derive_umi_tagged(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput);
let name = &input.ident;
let generics = &input.generics;
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
let field_name = get_umi_field_name(&input);
let field_ident = syn::Ident::new(&field_name, proc_macro2::Span::call_site());
let expanded = quote! {
impl #impl_generics UmiTaggedRecord for #name #ty_generics #where_clause {
fn umi(&self) -> u64 {
self.#field_ident
}
}
};
TokenStream::from(expanded)
}
fn get_umi_field_name(input: &DeriveInput) -> String {
for attr in &input.attrs {
if attr.path().is_ident("umi_tagged")
&& let Meta::List(meta_list) = &attr.meta
{
let tokens = &meta_list.tokens;
let parsed: Result<MetaNameValue, _> = syn::parse2(tokens.clone());
if let Ok(nv) = parsed
&& nv.path.is_ident("umi")
&& let syn::Expr::Lit(expr_lit) = &nv.value
&& let Lit::Str(lit_str) = &expr_lit.lit
{
return lit_str.value();
}
}
}
"umi".to_string()
}