1#![doc(html_root_url = "http://docs.rs/dyn-any-derive/0.1.0")]
2
3extern crate proc_macro;
4
5use proc_macro::TokenStream;
6use proc_macro2::Span;
7use quote::quote;
8use syn::{parse_macro_input, DeriveInput, GenericParam, Lifetime, LifetimeDef, TypeParamBound};
9
10#[proc_macro_derive(DynAny, attributes(dyn_any_derive))]
39pub fn system_desc_derive(input: TokenStream) -> TokenStream {
40 let ast = parse_macro_input!(input as DeriveInput);
41 let struct_name = &ast.ident;
42 let generics = &ast.generics;
43
44 let static_params = replace_lifetimes(generics, "'static");
45 let dyn_params = replace_lifetimes(generics, "'dyn_any");
46
47 let old_params = &generics.params.iter().collect::<Vec<_>>();
48 quote! {
49 unsafe impl<'dyn_any, #(#old_params,)*> StaticType for #struct_name <#(#dyn_params,)*> {
50 type Static = #struct_name <#(#static_params,)*>;
51 }
52 }
53 .into()
54}
55
56fn replace_lifetimes(generics: &syn::Generics, replacement: &str) -> Vec<proc_macro2::TokenStream> {
57 let params = generics
58 .params
59 .iter()
60 .map(|param| {
61 let param = match param {
62 GenericParam::Lifetime(_) => GenericParam::Lifetime(LifetimeDef::new(Lifetime::new(replacement, Span::call_site()))),
63 GenericParam::Type(t) => {
64 let mut t = t.clone();
65 t.bounds.iter_mut().for_each(|bond| {
66 if let TypeParamBound::Lifetime(ref mut t) = bond {
67 *t = Lifetime::new(replacement, Span::call_site())
68 }
69 });
70 GenericParam::Type(t.clone())
71 }
72 c => c.clone(),
73 };
74 quote! {#param}
75 })
76 .collect::<Vec<_>>();
77 params
78}