cbindgen/bindgen/
mangle.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5use crate::bindgen::config::MangleConfig;
6use crate::bindgen::ir::{ConstExpr, GenericArgument, GenericPath, Path, Type};
7use crate::bindgen::rename::IdentifierType;
8
9pub fn mangle_path(path: &Path, generic_values: &[GenericArgument], config: &MangleConfig) -> Path {
10    Path::new(mangle_name(path.name(), generic_values, config))
11}
12
13pub fn mangle_name(
14    name: &str,
15    generic_values: &[GenericArgument],
16    config: &MangleConfig,
17) -> String {
18    Mangler::new(name, generic_values, /* last = */ true, config).mangle()
19}
20
21enum Separator {
22    OpeningAngleBracket = 1,
23    Comma,
24    ClosingAngleBracket,
25    BeginMutPtr,
26    BeginConstPtr,
27    BeginFn,
28    BetweenFnArg,
29    EndFn,
30    BeginArray,
31    BetweenArray,
32}
33
34struct Mangler<'a> {
35    input: &'a str,
36    generic_values: &'a [GenericArgument],
37    output: String,
38    last: bool,
39    config: &'a MangleConfig,
40}
41
42impl<'a> Mangler<'a> {
43    fn new(
44        input: &'a str,
45        generic_values: &'a [GenericArgument],
46        last: bool,
47        config: &'a MangleConfig,
48    ) -> Self {
49        Self {
50            input,
51            generic_values,
52            output: String::new(),
53            last,
54            config,
55        }
56    }
57
58    fn mangle(mut self) -> String {
59        self.mangle_internal();
60        self.output
61    }
62
63    fn push(&mut self, id: Separator) {
64        let count = id as usize;
65        let separator = if self.config.remove_underscores {
66            ""
67        } else {
68            "_"
69        };
70        self.output.extend(std::iter::repeat(separator).take(count));
71    }
72
73    fn append_mangled_argument(&mut self, arg: &GenericArgument, last: bool) {
74        match *arg {
75            GenericArgument::Type(ref ty) => self.append_mangled_type(ty, last),
76            GenericArgument::Const(ConstExpr::Name(ref name)) => {
77                // This must behave the same as a GenericArgument::Type,
78                // because const arguments are commonly represented as Types;
79                // see the comment on `enum GenericArgument`.
80                let fake_ty = Type::Path(GenericPath::new(Path::new(name), vec![]));
81                self.append_mangled_type(&fake_ty, last);
82            }
83            GenericArgument::Const(ConstExpr::Value(ref val)) => self.output.push_str(val),
84        }
85    }
86
87    fn append_mangled_type(&mut self, ty: &Type, last: bool) {
88        match *ty {
89            Type::Path(ref generic) => {
90                let sub_path =
91                    Mangler::new(generic.export_name(), generic.generics(), last, self.config)
92                        .mangle();
93
94                self.output.push_str(
95                    &self
96                        .config
97                        .rename_types
98                        .apply(&sub_path, IdentifierType::Type),
99                );
100            }
101            Type::Primitive(ref primitive) => {
102                self.output.push_str(
103                    &self
104                        .config
105                        .rename_types
106                        .apply(primitive.to_repr_rust(), IdentifierType::Type),
107                );
108            }
109            Type::Ptr {
110                ref ty, is_const, ..
111            } => {
112                self.push(if is_const {
113                    Separator::BeginConstPtr
114                } else {
115                    Separator::BeginMutPtr
116                });
117                self.append_mangled_type(ty, last);
118            }
119            Type::FuncPtr {
120                ref ret, ref args, ..
121            } => {
122                self.push(Separator::BeginFn);
123                self.append_mangled_type(ret, args.is_empty());
124                for (i, arg) in args.iter().enumerate() {
125                    self.push(Separator::BetweenFnArg);
126                    let last = last && i == args.len() - 1;
127                    self.append_mangled_type(&arg.1, last);
128                }
129                if !self.last {
130                    self.push(Separator::EndFn);
131                }
132            }
133            Type::Array(ref ty, ref len) => {
134                self.push(Separator::BeginArray);
135                self.append_mangled_type(ty, false);
136                self.push(Separator::BetweenArray);
137                self.append_mangled_argument(&GenericArgument::Const(len.clone()), last);
138            }
139        }
140    }
141
142    fn mangle_internal(&mut self) {
143        debug_assert!(self.output.is_empty());
144        self.input.clone_into(&mut self.output);
145        if self.generic_values.is_empty() {
146            return;
147        }
148
149        self.push(Separator::OpeningAngleBracket);
150        for (i, arg) in self.generic_values.iter().enumerate() {
151            if i != 0 {
152                self.push(Separator::Comma);
153            }
154            let last = self.last && i == self.generic_values.len() - 1;
155            self.append_mangled_argument(arg, last);
156        }
157
158        // Skip writing the trailing '>' mangling when possible
159        if !self.last {
160            self.push(Separator::ClosingAngleBracket)
161        }
162    }
163}
164
165#[test]
166fn generics() {
167    use crate::bindgen::ir::{GenericPath, PrimitiveType};
168    use crate::bindgen::rename::RenameRule::{self, PascalCase};
169
170    fn float() -> GenericArgument {
171        GenericArgument::Type(Type::Primitive(PrimitiveType::Float))
172    }
173
174    fn c_char() -> GenericArgument {
175        GenericArgument::Type(Type::Primitive(PrimitiveType::Char))
176    }
177
178    fn path(path: &str) -> GenericArgument {
179        generic_path(path, &[])
180    }
181
182    fn generic_path(path: &str, arguments: &[GenericArgument]) -> GenericArgument {
183        let path = Path::new(path);
184        let generic_path = GenericPath::new(path, arguments.to_owned());
185        GenericArgument::Type(Type::Path(generic_path))
186    }
187
188    // Foo<f32> => Foo_f32
189    assert_eq!(
190        mangle_path(&Path::new("Foo"), &[float()], &MangleConfig::default()),
191        Path::new("Foo_f32")
192    );
193
194    // Foo<Bar<f32>> => Foo_Bar_f32
195    assert_eq!(
196        mangle_path(
197            &Path::new("Foo"),
198            &[generic_path("Bar", &[float()])],
199            &MangleConfig::default(),
200        ),
201        Path::new("Foo_Bar_f32")
202    );
203
204    // Foo<Bar> => Foo_Bar
205    assert_eq!(
206        mangle_path(&Path::new("Foo"), &[path("Bar")], &MangleConfig::default()),
207        Path::new("Foo_Bar")
208    );
209
210    // Foo<Bar> => FooBar
211    assert_eq!(
212        mangle_path(
213            &Path::new("Foo"),
214            &[path("Bar")],
215            &MangleConfig {
216                remove_underscores: true,
217                rename_types: RenameRule::None,
218            }
219        ),
220        Path::new("FooBar")
221    );
222
223    // Foo<Bar<f32>> => FooBarF32
224    assert_eq!(
225        mangle_path(
226            &Path::new("Foo"),
227            &[generic_path("Bar", &[float()])],
228            &MangleConfig {
229                remove_underscores: true,
230                rename_types: PascalCase,
231            },
232        ),
233        Path::new("FooBarF32")
234    );
235
236    // Foo<Bar<c_char>> => FooBarCChar
237    assert_eq!(
238        mangle_path(
239            &Path::new("Foo"),
240            &[generic_path("Bar", &[c_char()])],
241            &MangleConfig {
242                remove_underscores: true,
243                rename_types: PascalCase,
244            },
245        ),
246        Path::new("FooBarCChar")
247    );
248
249    // Foo<Bar<T>> => Foo_Bar_T
250    assert_eq!(
251        mangle_path(
252            &Path::new("Foo"),
253            &[generic_path("Bar", &[path("T")])],
254            &MangleConfig::default(),
255        ),
256        Path::new("Foo_Bar_T")
257    );
258
259    // Foo<Bar<T>, E> => Foo_Bar_T_____E
260    assert_eq!(
261        mangle_path(
262            &Path::new("Foo"),
263            &[generic_path("Bar", &[path("T")]), path("E")],
264            &MangleConfig::default(),
265        ),
266        Path::new("Foo_Bar_T_____E")
267    );
268
269    // Foo<Bar<T>, Bar<E>> => Foo_Bar_T_____Bar_E
270    assert_eq!(
271        mangle_path(
272            &Path::new("Foo"),
273            &[
274                generic_path("Bar", &[path("T")]),
275                generic_path("Bar", &[path("E")]),
276            ],
277            &MangleConfig::default(),
278        ),
279        Path::new("Foo_Bar_T_____Bar_E")
280    );
281
282    // Foo<Bar<T>, E> => FooBarTE
283    assert_eq!(
284        mangle_path(
285            &Path::new("Foo"),
286            &[generic_path("Bar", &[path("T")]), path("E")],
287            &MangleConfig {
288                remove_underscores: true,
289                rename_types: PascalCase,
290            },
291        ),
292        Path::new("FooBarTE")
293    );
294
295    // Foo<Bar<T>, Bar<E>> => FooBarTBarE
296    assert_eq!(
297        mangle_path(
298            &Path::new("Foo"),
299            &[
300                generic_path("Bar", &[path("T")]),
301                generic_path("Bar", &[path("E")]),
302            ],
303            &MangleConfig {
304                remove_underscores: true,
305                rename_types: PascalCase,
306            },
307        ),
308        Path::new("FooBarTBarE")
309    );
310
311    assert_eq!(
312        mangle_path(
313            &Path::new("Top"),
314            &[GenericArgument::Const(ConstExpr::Value("40".to_string()))],
315            &MangleConfig::default(),
316        ),
317        Path::new("Top_40")
318    );
319
320    assert_eq!(
321        mangle_path(
322            &Path::new("Top"),
323            &[GenericArgument::Const(ConstExpr::Name("N".to_string()))],
324            &MangleConfig::default(),
325        ),
326        Path::new("Top_N")
327    );
328
329    assert_eq!(
330        mangle_path(
331            &Path::new("Top"),
332            &[generic_path("N", &[])],
333            &MangleConfig::default(),
334        ),
335        Path::new("Top_N")
336    );
337
338    assert_eq!(
339        mangle_path(
340            &Path::new("Foo"),
341            &[
342                float(),
343                GenericArgument::Const(ConstExpr::Value("40".to_string()))
344            ],
345            &MangleConfig::default(),
346        ),
347        Path::new("Foo_f32__40")
348    );
349}