1use std::any::Any;
2use std::fmt::{Debug, Display};
3use std::mem::take;
4
5use inflector::Inflector;
6use proc_macro2::Ident as Ident2;
7use quote::format_ident;
8
9use crate::models::{
10 meta::{MetaType, MetaTypeVariant, MetaTypes},
11 schema::{MaxOccurs, NamespaceId},
12 Ident, Name,
13};
14
15pub trait Naming: Debug {
20 fn clone_boxed(&self) -> Box<dyn Naming>;
22
23 fn builder(&self) -> Box<dyn NameBuilder>;
25
26 fn unify(&self, s: &str) -> String {
35 let mut done = true;
36 let s = s.replace(
37 |c: char| {
38 let replace = !c.is_alphanumeric();
39 if c != '_' && !replace {
40 done = false;
41 }
42
43 c != '_' && replace
44 },
45 "_",
46 );
47
48 if done {
49 s
50 } else {
51 s.to_screaming_snake_case().to_pascal_case()
52 }
53 }
54
55 fn format_type_name(&self, s: &str) -> String {
59 let mut name = self.unify(s);
60
61 if let Ok(idx) = KEYWORDS.binary_search_by(|(key, _)| key.cmp(&&*name)) {
62 name = KEYWORDS[idx].1.into();
63 }
64
65 if name.starts_with(char::is_numeric) {
66 name = format!("_{name}");
67 }
68
69 name
70 }
71
72 fn format_field_name(&self, s: &str) -> String {
76 let mut name = self.unify(s).to_snake_case();
77
78 if let Ok(idx) = KEYWORDS.binary_search_by(|(key, _)| key.cmp(&&*name)) {
79 name = KEYWORDS[idx].1.into();
80 }
81
82 if name.starts_with(char::is_numeric) {
83 name = format!("_{name}");
84 }
85
86 name
87 }
88
89 fn format_variant_name(&self, s: &str) -> String {
93 self.format_type_name(s)
94 }
95
96 fn format_module_name(&self, s: &str) -> String {
100 self.format_field_name(s)
101 }
102
103 fn format_type_ident(&self, name: &Name, display_name: Option<&str>) -> Ident2 {
109 let ident = self.format_type_name(display_name.unwrap_or(name.as_str()));
110
111 format_ident!("{ident}")
112 }
113
114 fn format_field_ident(&self, name: &Name, display_name: Option<&str>) -> Ident2 {
120 let ident = self.format_field_name(display_name.unwrap_or(name.as_str()));
121
122 format_ident!("{ident}")
123 }
124
125 fn format_variant_ident(&self, name: &Name, display_name: Option<&str>) -> Ident2 {
130 self.format_type_ident(name, display_name)
131 }
132
133 fn format_module_ident(&self, name: &Name) -> Ident2 {
138 self.format_field_ident(name, None)
139 }
140
141 fn format_module(&self, types: &MetaTypes, ns: Option<NamespaceId>) -> Option<Ident2> {
143 let ns = ns?;
144 let module = types.modules.get(&ns)?;
145 let name = module.name.as_ref()?;
146
147 Some(self.format_module_ident(name))
148 }
149
150 fn make_type_name(&self, postfixes: &[String], ty: &MetaType, ident: &Ident) -> Name {
153 if let MetaTypeVariant::Reference(ti) = &ty.variant {
154 if ident.name.is_generated() && ti.type_.name.is_named() {
155 let s = self.format_type_name(ti.type_.name.as_str());
156
157 if ti.max_occurs > MaxOccurs::Bounded(1) {
158 return Name::new_generated(format!("{s}List"));
159 } else if ti.min_occurs == 0 {
160 return Name::new_generated(format!("{s}Opt"));
161 }
162 }
163 }
164
165 let postfix = postfixes
166 .get(ident.type_ as usize)
167 .map_or("", |s| s.as_str());
168
169 let s = self.format_type_name(ident.name.as_str());
170
171 if s.ends_with(postfix) {
172 ident.name.clone()
173 } else {
174 Name::new_generated(format!("{s}{postfix}"))
175 }
176 }
177
178 fn make_unknown_variant(&self, id: usize) -> Ident2 {
182 format_ident!("Unknown{id}")
183 }
184}
185
186pub trait NameBuilder: Debug + Any {
201 fn finish(&self) -> Name;
204
205 fn merge(&mut self, other: &dyn NameBuilder);
208
209 fn clone_boxed(&self) -> Box<dyn NameBuilder>;
211
212 fn has_name(&self) -> bool;
214
215 fn has_extension(&self) -> bool;
217
218 fn set_name(&mut self, name: String);
220
221 fn set_with_id(&mut self, value: bool);
223
224 fn set_generated(&mut self, value: bool);
227
228 fn add_extension(&mut self, replace: bool, extension: String);
231
232 fn strip_suffix(&mut self, suffix: &str);
234
235 fn generate_unique_id(&mut self);
243}
244
245impl NameBuilder for Box<dyn NameBuilder> {
246 #[inline]
247 fn finish(&self) -> Name {
248 (**self).finish()
249 }
250
251 #[inline]
252 fn merge(&mut self, other: &dyn NameBuilder) {
253 (**self).merge(other);
254 }
255
256 #[inline]
257 fn clone_boxed(&self) -> Box<dyn NameBuilder> {
258 (**self).clone_boxed()
259 }
260
261 #[inline]
262 fn has_name(&self) -> bool {
263 (**self).has_name()
264 }
265
266 #[inline]
267 fn has_extension(&self) -> bool {
268 (**self).has_extension()
269 }
270
271 #[inline]
272 fn set_name(&mut self, name: String) {
273 (**self).set_name(name);
274 }
275
276 #[inline]
277 fn set_with_id(&mut self, value: bool) {
278 (**self).set_with_id(value);
279 }
280
281 #[inline]
282 fn set_generated(&mut self, value: bool) {
283 (**self).set_generated(value);
284 }
285
286 #[inline]
287 fn add_extension(&mut self, replace: bool, extension: String) {
288 (**self).add_extension(replace, extension);
289 }
290
291 #[inline]
292 fn strip_suffix(&mut self, suffix: &str) {
293 (**self).strip_suffix(suffix);
294 }
295
296 #[inline]
297 fn generate_unique_id(&mut self) {
298 (**self).generate_unique_id();
299 }
300}
301
302pub trait NameBuilderExt: Sized {
304 #[must_use]
306 fn generate_id(self) -> Self;
307
308 #[must_use]
311 fn with_id(self, value: bool) -> Self;
312
313 #[must_use]
317 fn extend<I>(self, replace: bool, iter: I) -> Self
318 where
319 I: IntoIterator,
320 I::Item: Display;
321
322 #[must_use]
324 fn remove_suffix(self, suffix: &str) -> Self;
325
326 #[must_use]
331 fn unique_name<T>(self, value: T) -> Self
332 where
333 T: Display;
334
335 #[must_use]
341 fn shared_name<T>(self, value: T) -> Self
342 where
343 T: Display;
344
345 #[must_use]
347 fn or<T>(self, fallback: T) -> Self
348 where
349 T: NameFallback;
350
351 #[must_use]
353 fn or_else<F, T>(self, fallback: F) -> Self
354 where
355 F: FnOnce() -> T,
356 T: NameFallback;
357}
358
359impl<X> NameBuilderExt for X
360where
361 X: NameBuilder + Sized,
362{
363 fn generate_id(mut self) -> Self {
364 self.generate_unique_id();
365
366 self
367 }
368
369 fn with_id(mut self, value: bool) -> Self {
370 self.set_with_id(value);
371
372 self
373 }
374
375 fn extend<I>(mut self, mut replace: bool, iter: I) -> Self
376 where
377 I: IntoIterator,
378 I::Item: Display,
379 {
380 for ext in iter {
381 let ext = ext.to_string();
382
383 self.add_extension(take(&mut replace), ext);
384 }
385
386 self
387 }
388
389 fn remove_suffix(mut self, suffix: &str) -> Self {
390 self.strip_suffix(suffix);
391
392 self
393 }
394
395 fn unique_name<T>(mut self, value: T) -> Self
396 where
397 T: Display,
398 {
399 self.set_name(value.to_string());
400 self.set_with_id(false);
401
402 self
403 }
404
405 fn shared_name<T>(mut self, value: T) -> Self
406 where
407 T: Display,
408 {
409 self.set_name(value.to_string());
410 self.set_with_id(true);
411
412 self
413 }
414
415 fn or<T>(self, fallback: T) -> Self
416 where
417 T: NameFallback,
418 {
419 self.or_else(|| fallback)
420 }
421
422 fn or_else<F, T>(mut self, fallback: F) -> Self
423 where
424 F: FnOnce() -> T,
425 T: NameFallback,
426 {
427 if !self.has_name() {
428 fallback().apply(&mut self);
429 }
430
431 self
432 }
433}
434
435pub trait NameFallback {
438 fn apply(self, builder: &mut dyn NameBuilder);
440}
441
442impl NameFallback for &dyn NameBuilder {
443 fn apply(self, builder: &mut dyn NameBuilder) {
444 builder.merge(self);
445 }
446}
447
448impl NameFallback for Box<dyn NameBuilder> {
449 fn apply(self, builder: &mut dyn NameBuilder) {
450 builder.merge(&*self);
451 }
452}
453
454impl NameFallback for Name {
455 #[inline]
456 fn apply(self, builder: &mut dyn NameBuilder) {
457 (&self).apply(builder);
458 }
459}
460
461impl NameFallback for &Name {
462 #[inline]
463 fn apply(self, builder: &mut dyn NameBuilder) {
464 builder.set_name(self.as_str().to_owned());
465 builder.set_generated(self.is_generated());
466 builder.set_with_id(false);
467 }
468}
469
470impl NameFallback for Option<&Name> {
471 #[inline]
472 fn apply(self, builder: &mut dyn NameBuilder) {
473 if let Some(x) = self {
474 x.apply(builder);
475 }
476 }
477}
478
479impl NameFallback for Option<Name> {
480 #[inline]
481 fn apply(self, builder: &mut dyn NameBuilder) {
482 self.as_ref().apply(builder);
483 }
484}
485
486impl NameFallback for &Option<Name> {
487 fn apply(self, builder: &mut dyn NameBuilder) {
488 self.as_ref().apply(builder);
489 }
490}
491
492impl NameFallback for &String {
493 fn apply(self, builder: &mut dyn NameBuilder) {
494 builder.set_name(self.to_owned());
495 builder.set_with_id(false);
496 }
497}
498
499impl NameFallback for Option<&String> {
500 fn apply(self, builder: &mut dyn NameBuilder) {
501 if let Some(x) = self {
502 x.apply(builder);
503 }
504 }
505}
506
507impl NameFallback for Option<String> {
508 fn apply(self, builder: &mut dyn NameBuilder) {
509 self.as_ref().apply(builder);
510 }
511}
512
513impl NameFallback for &Option<String> {
514 fn apply(self, builder: &mut dyn NameBuilder) {
515 self.as_ref().apply(builder);
516 }
517}
518
519impl NameFallback for &str {
520 fn apply(self, builder: &mut dyn NameBuilder) {
521 builder.set_name(self.to_owned());
522 builder.set_with_id(false);
523 }
524}
525
526impl NameFallback for Option<&str> {
527 fn apply(self, builder: &mut dyn NameBuilder) {
528 if let Some(x) = self {
529 x.apply(builder);
530 }
531 }
532}
533
534const KEYWORDS: &[(&str, &str)] = &[
537 ("Self", "Self_"),
538 ("abstract", "abstract_"),
539 ("as", "as_"),
540 ("become", "become_"),
541 ("box", "box_"),
542 ("break", "break_"),
543 ("const", "const_"),
544 ("continue", "continue_"),
545 ("crate", "crate_"),
546 ("do", "do_"),
547 ("else", "else_"),
548 ("enum", "enum_"),
549 ("extern", "extern_"),
550 ("false", "false_"),
551 ("final", "final_"),
552 ("fn", "fn_"),
553 ("for", "for_"),
554 ("if", "if_"),
555 ("impl", "impl_"),
556 ("in", "in_"),
557 ("let", "let_"),
558 ("loop", "loop_"),
559 ("macro", "macro_"),
560 ("match", "match_"),
561 ("mod", "mod_"),
562 ("move", "move_"),
563 ("mut", "mut_"),
564 ("override", "override_"),
565 ("priv", "priv_"),
566 ("pub", "pub_"),
567 ("ref", "ref_"),
568 ("return", "return_"),
569 ("self", "self_"),
570 ("static", "static_"),
571 ("struct", "struct_"),
572 ("super", "super_"),
573 ("trait", "trait_"),
574 ("true", "true_"),
575 ("try", "try_"),
576 ("type", "type_"),
577 ("typeof", "typeof_"),
578 ("union", "union_"),
579 ("unsafe", "unsafe_"),
580 ("unsized", "unsized_"),
581 ("use", "use_"),
582 ("virtual", "virtual_"),
583 ("where", "where_"),
584 ("while", "while_"),
585 ("yield", "yield_"),
586];
587
588#[cfg(test)]
589mod tests {
590 use super::KEYWORDS;
591
592 #[test]
593 fn verify_keyword_order() {
594 for i in 1..KEYWORDS.len() {
595 assert!(dbg!(KEYWORDS[i - 1].0) < dbg!(KEYWORDS[i].0));
596 }
597 }
598}