cxx_build/syntax/
mangle.rs

1// Mangled symbol arrangements:
2//
3//   (a) One-off internal symbol.
4//          pattern:  {CXXBRIDGE} $ {NAME}
5//          examples:
6//             - cxxbridge1$exception
7//          defining characteristics:
8//             - 2 segments, none an integer
9//
10//   (b) Behavior on a builtin binding without generic parameter.
11//          pattern:  {CXXBRIDGE} $ {TYPE} $ {NAME}
12//          examples:
13//             - cxxbridge1$string$len
14//          defining characteristics:
15//             - 3 segments, none an integer
16//
17//   (c) Behavior on a builtin binding with generic parameter.
18//          pattern:  {CXXBRIDGE} $ {TYPE} $ {PARAM...} $ {NAME}
19//          examples:
20//             - cxxbridge1$box$org$rust$Struct$alloc
21//             - cxxbridge1$unique_ptr$std$vector$u8$drop
22//          defining characteristics:
23//             - 4+ segments, none an integer
24//
25//   (d) User-defined extern function.
26//          pattern:  {NAMESPACE...} $ {CXXBRIDGE} $ {CXXVERSION} $ {NAME}
27//          examples:
28//             - cxxbridge1$189$new_client
29//             - org$rust$cxxbridge1$189$new_client
30//          defining characteristics:
31//             - second segment from end is an integer
32//
33//   (e) User-defined extern member function.
34//          pattern:  {NAMESPACE...} $ {CXXBRIDGE} $ {CXXVERSION} $ {TYPE} $ {NAME}
35//          examples:
36//             - org$cxxbridge1$189$Struct$get
37//          defining characteristics:
38//             - third segment from end is an integer
39//
40//   (f) Operator overload.
41//          pattern:  {NAMESPACE...} $ {CXXBRIDGE} $ {CXXVERSION} $ {TYPE} $ operator $ {NAME}
42//          examples:
43//             - org$rust$cxxbridge1$189$Struct$operator$eq
44//          defining characteristics:
45//             - second segment from end is `operator` (not possible in type or namespace names)
46//
47//   (g) Closure trampoline.
48//          pattern:  {NAMESPACE...} $ {CXXBRIDGE} $ {CXXVERSION} $ {TYPE?} $ {NAME} $ {ARGUMENT} $ {DIRECTION}
49//          examples:
50//             - org$rust$cxxbridge1$Struct$invoke$f$0
51//          defining characteristics:
52//             - last symbol is `0` (C half) or `1` (Rust half) which are not legal identifiers on their own
53//
54//
55// Mangled preprocessor variable arrangements:
56//
57//   (A) One-off internal variable.
58//          pattern:  {CXXBRIDGE} _ {NAME}
59//          examples:
60//             - CXXBRIDGE1_PANIC
61//             - CXXBRIDGE1_RUST_STRING
62//          defining characteristics:
63//             - NAME does not begin with STRUCT or ENUM
64//
65//   (B) Guard around user-defined type.
66//          pattern:  {CXXBRIDGE} _ {STRUCT or ENUM} _ {NAMESPACE...} $ {TYPE}
67//          examples:
68//             - CXXBRIDGE1_STRUCT_org$rust$Struct
69//             - CXXBRIDGE1_ENUM_Enabled
70
71use crate::syntax::map::UnorderedMap;
72use crate::syntax::resolve::Resolution;
73use crate::syntax::symbol::{self, Symbol};
74use crate::syntax::{ExternFn, Pair, Type, Types};
75use proc_macro2::Ident;
76
77const CXXBRIDGE: &str = "cxxbridge1";
78const CXXVERSION: &str = "189"env!("CARGO_PKG_VERSION_PATCH");
79
80macro_rules! join {
81    ($($segment:expr),+ $(,)?) => {
82        symbol::join(&[$(&$segment),+])
83    };
84}
85
86pub(crate) fn extern_fn(efn: &ExternFn, types: &Types) -> Symbol {
87    match efn.self_type() {
88        Some(self_type) => {
89            let self_type_ident = types.resolve(self_type);
90            symbol::join(&[&efn.name.namespace, &CXXBRIDGE, &CXXVERSION,
                &self_type_ident.name.cxx, &efn.name.rust])join!(
91                efn.name.namespace,
92                CXXBRIDGE,
93                CXXVERSION,
94                self_type_ident.name.cxx,
95                efn.name.rust,
96            )
97        }
98        None => symbol::join(&[&efn.name.namespace, &CXXBRIDGE, &CXXVERSION, &efn.name.rust])join!(efn.name.namespace, CXXBRIDGE, CXXVERSION, efn.name.rust),
99    }
100}
101
102pub(crate) fn operator(receiver: &Pair, operator: &'static str) -> Symbol {
103    symbol::join(&[&receiver.namespace, &CXXBRIDGE, &CXXVERSION, &receiver.cxx,
                &"operator", &operator])join!(
104        receiver.namespace,
105        CXXBRIDGE,
106        CXXVERSION,
107        receiver.cxx,
108        "operator",
109        operator,
110    )
111}
112
113// The C half of a function pointer trampoline.
114pub(crate) fn c_trampoline(efn: &ExternFn, var: &Pair, types: &Types) -> Symbol {
115    symbol::join(&[&extern_fn(efn, types), &var.rust, &0])join!(extern_fn(efn, types), var.rust, 0)
116}
117
118// The Rust half of a function pointer trampoline.
119pub(crate) fn r_trampoline(efn: &ExternFn, var: &Pair, types: &Types) -> Symbol {
120    symbol::join(&[&extern_fn(efn, types), &var.rust, &1])join!(extern_fn(efn, types), var.rust, 1)
121}
122
123/// Mangles the given type (e.g. `Box<org::rust::Struct>`) into a symbol
124/// fragment (`box$org$rust$Struct`) to be used in the name of generic
125/// instantiations (`cxxbridge1$box$org$rust$Struct$alloc`) pertaining to that
126/// type.
127///
128/// Generic instantiation is not supported for all types in full generality.
129/// This function must handle unsupported types gracefully by returning `None`
130/// because it is used early during construction of the data structures that are
131/// the input to 'syntax/check.rs', and unsupported generic instantiations are
132/// only reported as an error later.
133pub(crate) fn typename(t: &Type, res: &UnorderedMap<&Ident, Resolution>) -> Option<Symbol> {
134    match t {
135        Type::Ident(named_type) => res.get(&named_type.rust).map(|res| res.name.to_symbol()),
136        Type::CxxVector(ty1) => typename(&ty1.inner, res).map(|s| symbol::join(&[&"std", &"vector", &s])join!("std", "vector", s)),
137        _ => None,
138    }
139}