dyn_any_derive/
lib.rs

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/// Derives an implementation for the [`DynAny`] trait.
11///
12/// # Note
13///
14/// Currently only works with `struct` inputs.
15///
16/// # Example
17///
18/// ## Struct
19///
20/// ```
21/// # use dyn_any::{DynAny, StaticType};
22/// #[derive(DynAny)]
23/// pub struct Color<'a, 'b> {
24///     r: &'a u8,
25///     g: &'b u8,
26///     b: &'a u8,
27/// }
28///
29///
30/// // Generated Impl
31///
32/// // impl<'dyn_any> StaticType for Color<'dyn_any, 'dyn_any> {
33/// //     type Static = Color<'static, 'static>;
34/// // }
35///
36/// ```
37
38#[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}