cxxbridge_macro/
generics.rs

1use crate::expand::display_namespaced;
2use crate::syntax::instantiate::NamedImplKey;
3use crate::syntax::types::ConditionalImpl;
4use crate::syntax::{Lifetimes, NamedType, Type, Types};
5use proc_macro2::TokenStream;
6use 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        types.resolve(local_type(key.inner)).generics
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            _ => {
    ::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"),
65        }
66    }
67}
68
69pub(crate) fn local_type(ty: &Type) -> &NamedType {
70    match ty {
71        Type::Ident(named_type) => named_type,
72        _ => {
    ::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"),
73    }
74}
75
76pub(crate) fn concise_rust_name(ty: &Type) -> String {
77    match ty {
78        Type::Ident(named_type) => named_type.rust.to_string(),
79        _ => {
    ::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"),
80    }
81}
82
83pub(crate) fn concise_cxx_name(ty: &Type, types: &Types) -> String {
84    match ty {
85        Type::Ident(named_type) => {
86            let res = types.resolve(&named_type.rust);
87            display_namespaced(res.name).to_string()
88        }
89        _ => {
    ::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"),
90    }
91}
92
93pub(crate) struct UnderscoreLifetimes<'a> {
94    generics: &'a Lifetimes,
95}
96
97impl Lifetimes {
98    pub(crate) fn to_underscore_lifetimes(&self) -> UnderscoreLifetimes {
99        UnderscoreLifetimes { generics: self }
100    }
101}
102
103impl<'a> ToTokens for UnderscoreLifetimes<'a> {
104    fn to_tokens(&self, tokens: &mut TokenStream) {
105        let Lifetimes {
106            lt_token,
107            lifetimes,
108            gt_token,
109        } = self.generics;
110        lt_token.to_tokens(tokens);
111        for pair in lifetimes.pairs() {
112            let (lifetime, punct) = pair.into_tuple();
113            let lifetime = Lifetime::new("'_", lifetime.span());
114            lifetime.to_tokens(tokens);
115            punct.to_tokens(tokens);
116        }
117        gt_token.to_tokens(tokens);
118    }
119}