asn1_rs_derive/
tostatic.rs

1use proc_macro2::Span;
2use quote::quote;
3use syn::{Ident, Lifetime};
4
5pub fn derive_tostatic(s: synstructure::Structure) -> proc_macro2::TokenStream {
6    let ast = s.ast();
7
8    let debug_derive = ast.attrs.iter().any(|attr| {
9        attr.meta
10            .path()
11            .is_ident(&Ident::new("debug_derive", Span::call_site()))
12    });
13
14    // if deriving a struct, there will be only one variant
15    // for enums, this will iterate on each variant
16    let body = s.each_variant(|vi| {
17        // bindings can be empty for unit variants
18        let instrs = vi
19            .bindings()
20            .iter()
21            .enumerate()
22            .fold(quote! {}, |acc, (idx, bi)| {
23                let ident = Ident::new(&format!("_{idx}"), Span::call_site());
24                quote! { #acc let #ident = #bi.to_static(); }
25            });
26        // use construct() to handle possible cases (unit/named/unnamed)
27        let c = vi.construct(|_f, i| {
28            let ident = Ident::new(&format!("_{i}"), Span::call_site());
29            quote! { #ident }
30        });
31        quote! { #instrs #c }
32    });
33
34    let struct_ident = &ast.ident;
35
36    // check if struct has lifetimes
37    let static_token = match ast.generics.lifetimes().count() {
38        0 => None,
39        1 => {
40            let lt = Lifetime::new("'static", Span::call_site());
41            Some(quote! {<#lt>})
42        }
43        _ => {
44            let lt_static = Lifetime::new("'static", Span::call_site());
45            let lts = ast.generics.lifetimes().map(|_| lt_static.clone());
46            Some(quote! {<#(#lts),*>})
47        }
48    };
49
50    let ts = s.gen_impl(quote! {
51        gen impl asn1_rs::ToStatic for @Self {
52            type Owned = #struct_ident #static_token;
53
54            fn to_static(&self) -> Self::Owned {
55                match *self {
56                    #body
57                }
58            }
59        }
60    });
61    if debug_derive {
62        eprintln!("TS: {ts}");
63    }
64    ts
65}