Skip to main content

libradicl_macros/
lib.rs

1use proc_macro::TokenStream;
2use quote::quote;
3use syn::{DeriveInput, Lit, Meta, MetaNameValue, parse_macro_input};
4
5#[proc_macro_derive(UmiTagged, attributes(umi_tagged))]
6pub fn derive_umi_tagged(input: TokenStream) -> TokenStream {
7    let input = parse_macro_input!(input as DeriveInput);
8
9    let name = &input.ident;
10    let generics = &input.generics;
11    let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
12
13    // Parse the attribute to get the field name
14    let field_name = get_umi_field_name(&input);
15
16    let field_ident = syn::Ident::new(&field_name, proc_macro2::Span::call_site());
17
18    let expanded = quote! {
19        impl #impl_generics UmiTaggedRecord for #name #ty_generics #where_clause {
20            fn umi(&self) -> u64 {
21                self.#field_ident
22            }
23        }
24    };
25
26    TokenStream::from(expanded)
27}
28
29fn get_umi_field_name(input: &DeriveInput) -> String {
30    for attr in &input.attrs {
31        if attr.path().is_ident("umi_tagged")
32            && let Meta::List(meta_list) = &attr.meta
33        {
34            let tokens = &meta_list.tokens;
35            let parsed: Result<MetaNameValue, _> = syn::parse2(tokens.clone());
36
37            if let Ok(nv) = parsed
38                && nv.path.is_ident("umi")
39                && let syn::Expr::Lit(expr_lit) = &nv.value
40                && let Lit::Str(lit_str) = &expr_lit.lit
41            {
42                return lit_str.value();
43            }
44        }
45    }
46
47    // Default to "umi" if no attribute is found
48    "umi".to_string()
49}