1use proc_macro::TokenStream;
2use proc_macro2::Span;
3use quote::quote;
4use syn::{ConstParam, GenericParam, Lifetime, LifetimeParam, TypeParam};
5
6#[proc_macro_derive(Zonbi)]
7pub fn derive_zonbi(input: TokenStream) -> TokenStream {
8 let ast = syn::parse_macro_input!(input as syn::DeriveInput);
9
10 let name = &ast.ident;
11 let generics = ast.generics;
12
13 let zonbi_life = Lifetime::new("'__zonbi_life", Span::call_site());
14
15 let mut zonbi_lifetimes = quote!();
16 for ig in &generics.params {
17 match ig {
18 GenericParam::Lifetime(_) => {
19 zonbi_lifetimes = quote! {
20 #zonbi_lifetimes
21 #zonbi_life ,
23 };
24 }
25 GenericParam::Const(ConstParam { ident, .. }) => {
26 zonbi_lifetimes = quote! {
27 #zonbi_lifetimes
28 #ident
29 ,
30 };
31 }
32 GenericParam::Type(TypeParam { ident, .. }) => {
33 zonbi_lifetimes = quote! {
34 #zonbi_lifetimes
35 #ident
36 ,
37 };
38 }
39 }
40 }
41
42 let mut generics2 = generics.clone();
43 let (_, ty_generics, _) = generics.split_for_impl();
44
45 let life_param = LifetimeParam::new(zonbi_life.clone());
46 generics2.params.push(GenericParam::Lifetime(life_param));
47
48 let (impl_generics, _, where_clause) = generics2.split_for_impl();
49 let other_clauses = where_clause.map(|w| &w.predicates);
50
51 quote! {
52 unsafe impl #impl_generics ::zonbi::Zonbi<#zonbi_life> for #name #ty_generics
53 where
54 Self: #zonbi_life,
55 #other_clauses
56 {
57 type Casted = #name<#zonbi_lifetimes>;
58
59 fn zonbi_id() -> ::zonbi::ZonbiId {
60 ::zonbi::ZonbiId::from(core::any::TypeId::of::<#name<'static>>())
61 }
62
63 unsafe fn zonbify(self) -> Self::Casted {
64 ::core::mem::transmute(self)
65 }
66
67 unsafe fn zonbify_ref(&self) -> &Self::Casted {
68 ::core::mem::transmute(self)
69 }
70
71 unsafe fn zonbify_mut(&mut self) -> &mut Self::Casted {
72 ::core::mem::transmute(self)
73 }
74 }
75 }
76 .into()
77}