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