66 lines
1.9 KiB
Rust
66 lines
1.9 KiB
Rust
use proc_macro2::Span;
|
|
use quote::quote;
|
|
use syn::{Ident, Lifetime};
|
|
|
|
pub fn derive_tostatic(s: synstructure::Structure) -> proc_macro2::TokenStream {
|
|
let ast = s.ast();
|
|
|
|
let debug_derive = ast.attrs.iter().any(|attr| {
|
|
attr.meta
|
|
.path()
|
|
.is_ident(&Ident::new("debug_derive", Span::call_site()))
|
|
});
|
|
|
|
// if deriving a struct, there will be only one variant
|
|
// for enums, this will iterate on each variant
|
|
let body = s.each_variant(|vi| {
|
|
// bindings can be empty for unit variants
|
|
let instrs = vi
|
|
.bindings()
|
|
.iter()
|
|
.enumerate()
|
|
.fold(quote! {}, |acc, (idx, bi)| {
|
|
let ident = Ident::new(&format!("_{idx}"), Span::call_site());
|
|
quote! { #acc let #ident = #bi.to_static(); }
|
|
});
|
|
// use construct() to handle possible cases (unit/named/unnamed)
|
|
let c = vi.construct(|_f, i| {
|
|
let ident = Ident::new(&format!("_{i}"), Span::call_site());
|
|
quote! { #ident }
|
|
});
|
|
quote! { #instrs #c }
|
|
});
|
|
|
|
let struct_ident = &ast.ident;
|
|
|
|
// check if struct has lifetimes
|
|
let static_token = match ast.generics.lifetimes().count() {
|
|
0 => None,
|
|
1 => {
|
|
let lt = Lifetime::new("'static", Span::call_site());
|
|
Some(quote! {<#lt>})
|
|
}
|
|
_ => {
|
|
let lt_static = Lifetime::new("'static", Span::call_site());
|
|
let lts = ast.generics.lifetimes().map(|_| lt_static.clone());
|
|
Some(quote! {<#(#lts),*>})
|
|
}
|
|
};
|
|
|
|
let ts = s.gen_impl(quote! {
|
|
gen impl asn1_rs::ToStatic for @Self {
|
|
type Owned = #struct_ident #static_token;
|
|
|
|
fn to_static(&self) -> Self::Owned {
|
|
match *self {
|
|
#body
|
|
}
|
|
}
|
|
}
|
|
});
|
|
if debug_derive {
|
|
eprintln!("TS: {ts}");
|
|
}
|
|
ts
|
|
}
|