abi_stable_derive/
get_static_equivalent.rs

1//! Stuff related to the `GetStaticEquivalent` derive macro.
2
3use 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
19/// The implementation of the `GetStaticEquivalent` derive macro.
20pub(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
41/// Tokenizes the `GetStaticEquivalent_` implementation for some type.
42fn 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}