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::{Path, Type};
7 use crate::bindgen::rename::IdentifierType;
8
mangle_path(path: &Path, generic_values: &[Type], config: &MangleConfig) -> Path9 pub fn mangle_path(path: &Path, generic_values: &[Type], config: &MangleConfig) -> Path {
10 Path::new(mangle_name(path.name(), generic_values, config))
11 }
12
mangle_name(name: &str, generic_values: &[Type], config: &MangleConfig) -> String13 pub fn mangle_name(name: &str, generic_values: &[Type], config: &MangleConfig) -> String {
14 Mangler::new(name, generic_values, /* last = */ true, config).mangle()
15 }
16
17 enum Separator {
18 OpeningAngleBracket = 1,
19 Comma,
20 ClosingAngleBracket,
21 BeginMutPtr,
22 BeginConstPtr,
23 BeginFn,
24 BetweenFnArg,
25 EndFn,
26 }
27
28 struct Mangler<'a> {
29 input: &'a str,
30 generic_values: &'a [Type],
31 output: String,
32 last: bool,
33 config: &'a MangleConfig,
34 }
35
36 impl<'a> Mangler<'a> {
new( input: &'a str, generic_values: &'a [Type], last: bool, config: &'a MangleConfig, ) -> Self37 fn new(
38 input: &'a str,
39 generic_values: &'a [Type],
40 last: bool,
41 config: &'a MangleConfig,
42 ) -> Self {
43 Self {
44 input,
45 generic_values,
46 output: String::new(),
47 last,
48 config,
49 }
50 }
51
mangle(mut self) -> String52 fn mangle(mut self) -> String {
53 self.mangle_internal();
54 self.output
55 }
56
push(&mut self, id: Separator)57 fn push(&mut self, id: Separator) {
58 let count = id as usize;
59 let separator = if self.config.remove_underscores {
60 ""
61 } else {
62 "_"
63 };
64 self.output.extend(std::iter::repeat(separator).take(count));
65 }
66
append_mangled_type(&mut self, ty: &Type, last: bool)67 fn append_mangled_type(&mut self, ty: &Type, last: bool) {
68 match *ty {
69 Type::Path(ref generic) => {
70 let sub_path =
71 Mangler::new(generic.export_name(), generic.generics(), last, self.config)
72 .mangle();
73
74 self.output.push_str(
75 &self
76 .config
77 .rename_types
78 .apply(&sub_path, IdentifierType::Type),
79 );
80 }
81 Type::Primitive(ref primitive) => {
82 self.output.push_str(
83 &self
84 .config
85 .rename_types
86 .apply(primitive.to_repr_rust(), IdentifierType::Type),
87 );
88 }
89 Type::Ptr {
90 ref ty, is_const, ..
91 } => {
92 self.push(if is_const {
93 Separator::BeginConstPtr
94 } else {
95 Separator::BeginMutPtr
96 });
97 self.append_mangled_type(&**ty, last);
98 }
99 Type::FuncPtr {
100 ref ret, ref args, ..
101 } => {
102 self.push(Separator::BeginFn);
103 self.append_mangled_type(&**ret, args.is_empty());
104 for (i, arg) in args.iter().enumerate() {
105 self.push(Separator::BetweenFnArg);
106 let last = last && i == args.len() - 1;
107 self.append_mangled_type(&arg.1, last);
108 }
109 if !self.last {
110 self.push(Separator::EndFn);
111 }
112 }
113 Type::Array(..) => {
114 unimplemented!(
115 "Unable to mangle generic parameter {:?} for '{}'",
116 ty,
117 self.input
118 );
119 }
120 }
121 }
122
mangle_internal(&mut self)123 fn mangle_internal(&mut self) {
124 debug_assert!(self.output.is_empty());
125 self.output = self.input.to_owned();
126 if self.generic_values.is_empty() {
127 return;
128 }
129
130 self.push(Separator::OpeningAngleBracket);
131 for (i, ty) in self.generic_values.iter().enumerate() {
132 if i != 0 {
133 self.push(Separator::Comma);
134 }
135 let last = self.last && i == self.generic_values.len() - 1;
136 self.append_mangled_type(ty, last);
137 }
138
139 // Skip writing the trailing '>' mangling when possible
140 if !self.last {
141 self.push(Separator::ClosingAngleBracket)
142 }
143 }
144 }
145
146 #[test]
generics()147 fn generics() {
148 use crate::bindgen::ir::{GenericPath, PrimitiveType};
149 use crate::bindgen::rename::RenameRule::{self, PascalCase};
150
151 fn float() -> Type {
152 Type::Primitive(PrimitiveType::Float)
153 }
154
155 fn c_char() -> Type {
156 Type::Primitive(PrimitiveType::Char)
157 }
158
159 fn path(path: &str) -> Type {
160 generic_path(path, &[])
161 }
162
163 fn generic_path(path: &str, generics: &[Type]) -> Type {
164 let path = Path::new(path);
165 let generic_path = GenericPath::new(path, generics.to_owned());
166 Type::Path(generic_path)
167 }
168
169 // Foo<f32> => Foo_f32
170 assert_eq!(
171 mangle_path(&Path::new("Foo"), &[float()], &MangleConfig::default()),
172 Path::new("Foo_f32")
173 );
174
175 // Foo<Bar<f32>> => Foo_Bar_f32
176 assert_eq!(
177 mangle_path(
178 &Path::new("Foo"),
179 &[generic_path("Bar", &[float()])],
180 &MangleConfig::default(),
181 ),
182 Path::new("Foo_Bar_f32")
183 );
184
185 // Foo<Bar> => Foo_Bar
186 assert_eq!(
187 mangle_path(&Path::new("Foo"), &[path("Bar")], &MangleConfig::default()),
188 Path::new("Foo_Bar")
189 );
190
191 // Foo<Bar> => FooBar
192 assert_eq!(
193 mangle_path(
194 &Path::new("Foo"),
195 &[path("Bar")],
196 &MangleConfig {
197 remove_underscores: true,
198 rename_types: RenameRule::None,
199 }
200 ),
201 Path::new("FooBar")
202 );
203
204 // Foo<Bar<f32>> => FooBarF32
205 assert_eq!(
206 mangle_path(
207 &Path::new("Foo"),
208 &[generic_path("Bar", &[float()])],
209 &MangleConfig {
210 remove_underscores: true,
211 rename_types: PascalCase,
212 },
213 ),
214 Path::new("FooBarF32")
215 );
216
217 // Foo<Bar<c_char>> => FooBarCChar
218 assert_eq!(
219 mangle_path(
220 &Path::new("Foo"),
221 &[generic_path("Bar", &[c_char()])],
222 &MangleConfig {
223 remove_underscores: true,
224 rename_types: PascalCase,
225 },
226 ),
227 Path::new("FooBarCChar")
228 );
229
230 // Foo<Bar<T>> => Foo_Bar_T
231 assert_eq!(
232 mangle_path(
233 &Path::new("Foo"),
234 &[generic_path("Bar", &[path("T")])],
235 &MangleConfig::default(),
236 ),
237 Path::new("Foo_Bar_T")
238 );
239
240 // Foo<Bar<T>, E> => Foo_Bar_T_____E
241 assert_eq!(
242 mangle_path(
243 &Path::new("Foo"),
244 &[generic_path("Bar", &[path("T")]), path("E")],
245 &MangleConfig::default(),
246 ),
247 Path::new("Foo_Bar_T_____E")
248 );
249
250 // Foo<Bar<T>, Bar<E>> => Foo_Bar_T_____Bar_E
251 assert_eq!(
252 mangle_path(
253 &Path::new("Foo"),
254 &[
255 generic_path("Bar", &[path("T")]),
256 generic_path("Bar", &[path("E")]),
257 ],
258 &MangleConfig::default(),
259 ),
260 Path::new("Foo_Bar_T_____Bar_E")
261 );
262
263 // Foo<Bar<T>, E> => FooBarTE
264 assert_eq!(
265 mangle_path(
266 &Path::new("Foo"),
267 &[generic_path("Bar", &[path("T")]), path("E")],
268 &MangleConfig {
269 remove_underscores: true,
270 rename_types: PascalCase,
271 },
272 ),
273 Path::new("FooBarTE")
274 );
275
276 // Foo<Bar<T>, Bar<E>> => FooBarTBarE
277 assert_eq!(
278 mangle_path(
279 &Path::new("Foo"),
280 &[
281 generic_path("Bar", &[path("T")]),
282 generic_path("Bar", &[path("E")]),
283 ],
284 &MangleConfig {
285 remove_underscores: true,
286 rename_types: PascalCase,
287 },
288 ),
289 Path::new("FooBarTBarE")
290 );
291 }
292