|
#![doc(html_root_url = "http://docs.rs/dyn-any-derive/0.1.0")] |
|
|
|
extern crate proc_macro; |
|
|
|
use proc_macro::TokenStream; |
|
use proc_macro2::Span; |
|
use quote::quote; |
|
use syn::{DeriveInput, GenericParam, Lifetime, LifetimeParam, TypeParamBound, parse_macro_input}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[proc_macro_derive(DynAny, attributes(dyn_any_derive))] |
|
pub fn system_desc_derive(input: TokenStream) -> TokenStream { |
|
let ast = parse_macro_input!(input as DeriveInput); |
|
let struct_name = &ast.ident; |
|
let generics = &ast.generics; |
|
|
|
let static_params = replace_lifetimes(generics, "'static"); |
|
let dyn_params = replace_lifetimes(generics, "'dyn_any"); |
|
|
|
let old_params = &generics.params.iter().collect::<Vec<_>>(); |
|
quote! { |
|
unsafe impl<'dyn_any, #(#old_params,)*> dyn_any::StaticType for #struct_name <#(#dyn_params,)*> { |
|
type Static = #struct_name <#(#static_params,)*>; |
|
} |
|
} |
|
.into() |
|
} |
|
|
|
fn replace_lifetimes(generics: &syn::Generics, replacement: &str) -> Vec<proc_macro2::TokenStream> { |
|
let params = generics |
|
.params |
|
.iter() |
|
.map(|param| { |
|
let param = match param { |
|
GenericParam::Lifetime(_) => GenericParam::Lifetime(LifetimeParam::new(Lifetime::new(replacement, Span::call_site()))), |
|
GenericParam::Type(t) => { |
|
let mut t = t.clone(); |
|
t.bounds.iter_mut().for_each(|bond| { |
|
if let TypeParamBound::Lifetime(t) = bond { |
|
*t = Lifetime::new(replacement, Span::call_site()) |
|
} |
|
}); |
|
GenericParam::Type(t.clone()) |
|
} |
|
c => c.clone(), |
|
}; |
|
quote! {#param} |
|
}) |
|
.collect::<Vec<_>>(); |
|
params |
|
} |
|
|