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 | |
5 | use crate::bindgen::config::MangleConfig; |
6 | use crate::bindgen::ir::{ConstExpr, GenericArgument, GenericPath, Path, Type}; |
7 | use crate::bindgen::rename::IdentifierType; |
8 | |
9 | pub fn mangle_path(path: &Path, generic_values: &[GenericArgument], config: &MangleConfig) -> Path { |
10 | Path::new(name:mangle_name(path.name(), generic_values, config)) |
11 | } |
12 | |
13 | pub 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 | |
21 | enum Separator { |
22 | OpeningAngleBracket = 1, |
23 | Comma, |
24 | ClosingAngleBracket, |
25 | BeginMutPtr, |
26 | BeginConstPtr, |
27 | BeginFn, |
28 | BetweenFnArg, |
29 | EndFn, |
30 | } |
31 | |
32 | struct Mangler<'a> { |
33 | input: &'a str, |
34 | generic_values: &'a [GenericArgument], |
35 | output: String, |
36 | last: bool, |
37 | config: &'a MangleConfig, |
38 | } |
39 | |
40 | impl<'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 ] |
165 | fn 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 | |