1use 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, 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 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 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 assert_eq!(
190 mangle_path(&Path::new("Foo"), &[float()], &MangleConfig::default()),
191 Path::new("Foo_f32")
192 );
193
194 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 assert_eq!(
206 mangle_path(&Path::new("Foo"), &[path("Bar")], &MangleConfig::default()),
207 Path::new("Foo_Bar")
208 );
209
210 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 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 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 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 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 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 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 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}