cxxbridge_macro/
generics.rs

1use crate::expand::display_namespaced;
2use crate::syntax::instantiate::NamedImplKey;
3use crate::syntax::types::ConditionalImpl;
4use crate::syntax::{Lifetimes, Type, Types};
5use proc_macro2::TokenStream;
6use quote::{quote, ToTokens};
7use syn::{Lifetime, Token};
8
9pub(crate) struct ResolvedGenericType<'a> {
10    ty: &'a Type,
11    explicit_impl: bool,
12    types: &'a Types<'a>,
13}
14
15/// Gets `(impl_generics, inner_with_generics)` pair that can be used when
16/// generating an `impl` for a generic type:
17///
18/// ```ignore
19/// quote! { impl #impl_generics SomeTrait for #inner_with_generics }
20/// ```
21pub(crate) fn split_for_impl<'a>(
22    key: &NamedImplKey<'a>,
23    conditional_impl: &ConditionalImpl<'a>,
24    types: &'a Types<'a>,
25) -> (&'a Lifetimes, ResolvedGenericType<'a>) {
26    let impl_generics = if let Some(explicit_impl) = conditional_impl.explicit_impl {
27        &explicit_impl.impl_generics
28    } else {
29        get_impl_generics(key.inner, types)
30    };
31    let ty_generics = ResolvedGenericType {
32        ty: key.inner,
33        explicit_impl: conditional_impl.explicit_impl.is_some(),
34        types,
35    };
36    (impl_generics, ty_generics)
37}
38
39impl<'a> ToTokens for ResolvedGenericType<'a> {
40    fn to_tokens(&self, tokens: &mut TokenStream) {
41        match self.ty {
42            Type::Ident(named_type) => {
43                named_type.rust.to_tokens(tokens);
44                if self.explicit_impl {
45                    named_type.generics.to_tokens(tokens);
46                } else {
47                    let resolve = self.types.resolve(named_type);
48                    if !resolve.generics.lifetimes.is_empty() {
49                        let span = named_type.rust.span();
50                        named_type
51                            .generics
52                            .lt_token
53                            .unwrap_or_else(|| ::syn::token::LtToken![<](span))
54                            .to_tokens(tokens);
55                        resolve.generics.lifetimes.to_tokens(tokens);
56                        named_type
57                            .generics
58                            .gt_token
59                            .unwrap_or_else(|| ::syn::token::GtToken![>](span))
60                            .to_tokens(tokens);
61                    }
62                }
63            }
64            Type::RustBox(ty1) => {
65                let inner = ResolvedGenericType {
66                    ty: &ty1.inner,
67                    explicit_impl: self.explicit_impl,
68                    types: self.types,
69                };
70                tokens.extend({
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "cxx");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "alloc");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "boxed");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "Box");
    ::quote::__private::push_lt(&mut _s);
    ::quote::ToTokens::to_tokens(&inner, &mut _s);
    ::quote::__private::push_gt(&mut _s);
    _s
}quote! {
71                    ::cxx::alloc::boxed::Box<#inner>
72                });
73            }
74            _ => {
    ::core::panicking::panic_fmt(format_args!("internal error: entered unreachable code: {0}",
            format_args!("syntax/check.rs should reject other types")));
}unreachable!("syntax/check.rs should reject other types"),
75        }
76    }
77}
78
79fn get_impl_generics<'a>(ty: &Type, types: &Types<'a>) -> &'a Lifetimes {
80    match ty {
81        Type::Ident(named_type) => types.resolve(named_type).generics,
82        Type::RustBox(ty1) => get_impl_generics(&ty1.inner, types),
83        _ => {
    ::core::panicking::panic_fmt(format_args!("internal error: entered unreachable code: {0}",
            format_args!("syntax/check.rs should reject other types")));
}unreachable!("syntax/check.rs should reject other types"),
84    }
85}
86
87pub(crate) fn format_for_prevent_unwind_label(ty: &Type) -> TokenStream {
88    match ty {
89        Type::Ident(named_type) => {
90            let rust_name = named_type.rust.to_string();
91            {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "cxx");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "core");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "concat");
    ::quote::__private::push_bang(&mut _s);
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Parenthesis,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "cxx");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "core");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "module_path");
            ::quote::__private::push_bang(&mut _s);
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Parenthesis,
                ::quote::__private::TokenStream::new());
            ::quote::__private::push_comma(&mut _s);
            ::quote::__private::parse(&mut _s, "\"::\"");
            ::quote::__private::push_comma(&mut _s);
            ::quote::ToTokens::to_tokens(&rust_name, &mut _s);
            _s
        });
    _s
}quote! {
92                ::cxx::core::concat!(::cxx::core::module_path!(), "::", #rust_name)
93            }
94        }
95        Type::RustBox(ty1) => {
96            let inner = format_for_prevent_unwind_label(&ty1.inner);
97            {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "cxx");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "core");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "concat");
    ::quote::__private::push_bang(&mut _s);
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Parenthesis,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::__private::parse(&mut _s, "\"Box<\"");
            ::quote::__private::push_comma(&mut _s);
            ::quote::ToTokens::to_tokens(&inner, &mut _s);
            ::quote::__private::push_comma(&mut _s);
            ::quote::__private::parse(&mut _s, "\">\"");
            _s
        });
    _s
}quote! {
98                ::cxx::core::concat!("Box<", #inner, ">")
99            }
100        }
101        _ => {
    ::core::panicking::panic_fmt(format_args!("internal error: entered unreachable code: {0}",
            format_args!("syntax/check.rs should reject other types")));
}unreachable!("syntax/check.rs should reject other types"),
102    }
103}
104
105pub(crate) fn concise_rust_name(ty: &Type) -> String {
106    match ty {
107        Type::Ident(named_type) => named_type.rust.to_string(),
108        Type::RustBox(ty1) => {
109            let inner = concise_rust_name(&ty1.inner);
110            ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("Box<{0}>", inner))
    })format!("Box<{inner}>")
111        }
112        _ => {
    ::core::panicking::panic_fmt(format_args!("internal error: entered unreachable code: {0}",
            format_args!("syntax/check.rs should reject other types")));
}unreachable!("syntax/check.rs should reject other types"),
113    }
114}
115
116pub(crate) fn concise_cxx_name(ty: &Type, types: &Types) -> String {
117    match ty {
118        Type::Ident(named_type) => {
119            let res = types.resolve(&named_type.rust);
120            display_namespaced(res.name).to_string()
121        }
122        Type::RustBox(ty1) => {
123            let inner = concise_cxx_name(&ty1.inner, types);
124            ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("rust::Box<{0}>", inner))
    })format!("rust::Box<{inner}>")
125        }
126        _ => {
    ::core::panicking::panic_fmt(format_args!("internal error: entered unreachable code: {0}",
            format_args!("syntax/check.rs should reject other types")));
}unreachable!("syntax/check.rs should reject other types"),
127    }
128}
129
130pub(crate) struct UnderscoreLifetimes<'a> {
131    generics: &'a Lifetimes,
132}
133
134impl Lifetimes {
135    pub(crate) fn to_underscore_lifetimes(&self) -> UnderscoreLifetimes {
136        UnderscoreLifetimes { generics: self }
137    }
138}
139
140impl<'a> ToTokens for UnderscoreLifetimes<'a> {
141    fn to_tokens(&self, tokens: &mut TokenStream) {
142        let Lifetimes {
143            lt_token,
144            lifetimes,
145            gt_token,
146        } = self.generics;
147        lt_token.to_tokens(tokens);
148        for pair in lifetimes.pairs() {
149            let (lifetime, punct) = pair.into_tuple();
150            let lifetime = Lifetime::new("'_", lifetime.span());
151            lifetime.to_tokens(tokens);
152            punct.to_tokens(tokens);
153        }
154        gt_token.to_tokens(tokens);
155    }
156}