abi_stable_derive/impl_interfacetype/
macro_impl.rs

1use super::*;
2
3use as_derive_utils::return_spanned_err;
4
5use proc_macro2::TokenStream as TokenStream2;
6
7use syn::{ImplItem, ImplItemType, ItemImpl, Visibility};
8
9/// The implementation of the impl_InterfaceType!{}` proc macro.
10///
11/// This macro takes in an impl block for the InterfaceType trait,
12/// and emulates defaulted associated types for the ones that weren't mentioned.
13pub fn the_macro(mut impl_: ItemImpl) -> Result<TokenStream2, syn::Error> {
14    let interfacetype: syn::Ident = syn::parse_str("InterfaceType").expect("BUG");
15
16    let mut const_name = (&impl_.self_ty).into_token_stream().to_string();
17    const_name.retain(|c| c.is_alphanumeric());
18    const_name.insert_str(0, "_impl_InterfaceType");
19    let const_name = parse_str_as_ident(&const_name);
20
21    let interface_path_s = impl_.trait_.as_ref().map(|x| &x.1.segments);
22    let is_interface_type = interface_path_s
23        .and_then(|x| x.last())
24        .map_or(false, |path_| path_.ident == interfacetype);
25
26    if !is_interface_type {
27        return_spanned_err!(
28            impl_,
29            "expected 'impl<...> InterfaceType for {} ' ",
30            impl_.self_ty.to_token_stream(),
31        );
32    }
33
34    // The default value for each associated type.
35    let mut default_map = TRAIT_LIST
36        .iter()
37        .map(|ut| {
38            (
39                parse_str_as_ident(ut.name),
40                DefaultVal::from(ut.which_trait.default_value()),
41            )
42        })
43        .collect::<HashMap<_, _>>();
44
45    // Processed the items in the impl block,
46    // removing them from the defaulted associated type map,
47    // and converting the value of the associated type to
48    // either `Implemented<trait_marker::AssocTyName>`
49    // or `Unimplemented<trait_marker::AssocTyName>`
50    for item in &mut impl_.items {
51        if let ImplItem::Type(assoc_ty) = item {
52            assert_ne!(
53                assoc_ty.ident, "define_this_in_the_impl_InterfaceType_macro",
54                "you are not supposed to define\n\t\
55                 the 'define_this_in_the_impl_InterfaceType_macro' associated type yourself"
56            );
57            default_map.remove(&assoc_ty.ident);
58
59            let old_ty = &assoc_ty.ty;
60            let name = &assoc_ty.ident;
61            let span = name.span();
62
63            assoc_ty.ty =
64                syn::Type::Verbatim(quote_spanned!(span=> ImplFrom<#old_ty, trait_marker::#name> ));
65        }
66    }
67
68    default_map.insert(private_associated_type(), DefaultVal::Hidden);
69
70    // Converts the defaulted associated types to the syn datastructure,
71    // and then adds them to the list of items inside the impl block.
72    for (key, default_) in default_map {
73        let mut attrs = Vec::<syn::Attribute>::new();
74
75        let span = key.span();
76
77        let ty = match default_ {
78            DefaultVal::Unimplemented => quote_spanned!(span=> Unimplemented<trait_marker::#key> ),
79            DefaultVal::Implemented => quote_spanned!(span=> Implemented<trait_marker::#key> ),
80            DefaultVal::Hidden => {
81                attrs.extend(parse_syn_attributes("#[doc(hidden)]").expect("BUG"));
82                quote_spanned!(span=> () )
83            }
84        }
85        .piped(syn::Type::Verbatim);
86
87        let defaulted = ImplItemType {
88            attrs,
89            vis: Visibility::Inherited,
90            defaultness: None,
91            type_token: Default::default(),
92            ident: key,
93            generics: Default::default(),
94            eq_token: Default::default(),
95            ty,
96            semi_token: Default::default(),
97        };
98        impl_.items.push(ImplItem::Type(defaulted))
99    }
100
101    quote!(
102        const #const_name:()={
103            use ::abi_stable::derive_macro_reexports::{
104                Implemented,
105                Unimplemented,
106                ImplFrom,
107                trait_marker,
108            };
109
110            #impl_
111        };
112    )
113    .piped(Ok)
114}
115
116/// Parses an inner attribute `#[]` from a string.
117///
118/// inner attribute as opposed to an outer attribute `#![]`.
119pub fn parse_syn_attributes(str_: &str) -> Result<Vec<syn::Attribute>, syn::Error> {
120    syn::parse_str::<ParseOuter>(str_).map(|x| x.attributes)
121}
122
123struct ParseOuter {
124    attributes: Vec<syn::Attribute>,
125}
126
127impl syn::parse::Parse for ParseOuter {
128    fn parse(input: syn::parse::ParseStream) -> syn::parse::Result<Self> {
129        Ok(Self {
130            attributes: syn::Attribute::parse_outer(input)?,
131        })
132    }
133}