abi_stable_derive/
get_static_equivalent.rs
1use proc_macro2::{Span, TokenStream as TokenStream2};
4
5use quote::{quote, ToTokens};
6
7use syn::{punctuated::Punctuated, DeriveInput, Generics, Ident};
8
9use as_derive_utils::{
10 gen_params_in::{GenParamsIn, InWhat},
11 to_stream,
12 to_token_fn::ToTokenFnMut,
13};
14
15use crate::{impl_interfacetype::impl_interfacetype_tokenizer, parse_utils::parse_str_as_ident};
16
17mod attribute_parsing;
18
19pub(crate) fn derive(data: DeriveInput) -> Result<TokenStream2, syn::Error> {
21 let name = &data.ident;
22 let generics = &data.generics;
23 let config = self::attribute_parsing::parse_attrs_for_get_static_equiv(&data.attrs)?;
24
25 let impl_it = impl_interfacetype_tokenizer(name, generics, config.impl_interfacetype.as_ref());
26 let gse_equiv_impl = get_static_equiv_tokenizer(name, generics, quote!());
27
28 let ret = quote!(
29 #impl_it
30
31 #gse_equiv_impl
32 );
33
34 if config.debug_print {
35 panic!("\n\n\n{}\n\n\n", ret);
36 }
37
38 Ok(ret)
39}
40
41fn get_static_equiv_tokenizer<'a>(
43 name: &'a Ident,
44 generics: &'a Generics,
45 extra_bounds: TokenStream2,
46) -> impl ToTokens + 'a {
47 ToTokenFnMut::new(move |ts| {
48 let lifetimes = &generics
49 .lifetimes()
50 .map(|x| &x.lifetime)
51 .collect::<Vec<_>>();
52 let type_params = &generics.type_params().map(|x| &x.ident).collect::<Vec<_>>();
53 let const_params = &generics
54 .const_params()
55 .map(|x| &x.ident)
56 .collect::<Vec<_>>();
57
58 let ct_gt = syn::token::Gt::default();
59 let ct_lt = syn::token::Lt::default();
60 let ct_static_equivalent = parse_str_as_ident("__GetStaticEquivalent");
61 let ct_comma = syn::token::Comma::default();
62 let ct_static_lt = syn::parse_str::<syn::Lifetime>("'static").expect("BUG");
63
64 let lifetimes_s = lifetimes.iter().map(|_| &ct_static_lt);
65 let type_params_s = ToTokenFnMut::new(|ts| {
66 for ty in type_params {
67 to_stream!(ts; ct_static_equivalent, ct_lt, ty, ct_gt, ct_comma);
68 }
69 });
70 let const_params_s = &const_params;
71
72 let (impl_generics, _, where_clause) = generics.split_for_impl();
73
74 let ty_generics = GenParamsIn::new(generics, InWhat::ItemUse);
75
76 let static_struct_name = Ident::new(&format!("_static_{}", name), Span::call_site());
77
78 let empty_preds = Punctuated::new();
79 let where_preds = where_clause
80 .as_ref()
81 .map_or(&empty_preds, |x| &x.predicates)
82 .into_iter();
83
84 let lifetimes_a = lifetimes;
85 let type_params_a = type_params;
86 let const_param_name = generics.const_params().map(|c| &c.ident);
87 let const_param_type = generics.const_params().map(|c| &c.ty);
88
89 let const_ident =
90 parse_str_as_ident(&format!("_impl_get_static_equivalent_constant_{}", name,));
91
92 quote!(
93 const #const_ident:()={
94 use ::abi_stable::derive_macro_reexports::renamed::{
95 __GetStaticEquivalent_,
96 __GetStaticEquivalent,
97 };
98
99 pub struct #static_struct_name<
100 #(#lifetimes_a,)*
101 #(#type_params_a:?Sized,)*
102 #(const #const_param_name:#const_param_type,)*
103 >(
104 #(& #lifetimes_a (),)*
105 extern "C" fn(#(&#type_params_a,)*)
106 );
107
108 unsafe impl #impl_generics __GetStaticEquivalent_ for #name <#ty_generics>
109 where
110 #(#where_preds,)*
111 #(#type_params_a:__GetStaticEquivalent_,)*
112 #extra_bounds
113 {
114 type StaticEquivalent=#static_struct_name <
115 #(#lifetimes_s,)*
116 #type_params_s
117 #({#const_params_s}),*
118 >;
119 }
120 };
121 )
122 .to_tokens(ts);
123 })
124}