Skip to main content

xsd_parser/models/naming/
mod.rs

1mod default;
2mod explicit;
3
4use std::borrow::Cow;
5
6use inflector::Inflector;
7use proc_macro2::Ident as Ident2;
8use quote::format_ident;
9
10use super::Name;
11
12pub use self::default::{NameBuilder, Naming};
13pub use self::explicit::{ExplicitNameBuilder, ExplicitNaming};
14
15/// Unify the passed string `s` into a standard format.
16#[must_use]
17pub fn unify_string(s: &str) -> String {
18    let mut done = true;
19    let s = s.replace(
20        |c: char| {
21            let replace = !c.is_alphanumeric();
22            if c != '_' && !replace {
23                done = false;
24            }
25
26            c != '_' && replace
27        },
28        "_",
29    );
30
31    if done {
32        s
33    } else {
34        s.to_screaming_snake_case().to_pascal_case()
35    }
36}
37
38/// Format an unknown variant identifier based on the passed `id`.
39#[must_use]
40pub fn format_unknown_variant(id: usize) -> Ident2 {
41    format_ident!("Unknown{id}")
42}
43
44/// Format the passed string `s` into a valid Rust identifier by adding an
45/// underscore if it starts with a numeric character or is a Rust keyword.
46#[must_use]
47pub fn format_ident<'a, S>(s: S) -> String
48where
49    S: Into<Cow<'a, str>>,
50{
51    let mut s = s.into();
52    if let Ok(idx) = KEYWORDS.binary_search_by(|(key, _)| key.cmp(&&*s)) {
53        s = Cow::Borrowed(KEYWORDS[idx].1);
54    }
55
56    if s.starts_with(char::is_numeric) {
57        s = Cow::Owned(format!("_{s}"));
58    }
59
60    s.replace(|c: char| !c.is_alphanumeric(), "_")
61}
62
63/// List of keywords that needs to be replaced by something else.
64/// This list needs to be sorted, because we use it in [`core::slice::binary_search_by`]
65const KEYWORDS: &[(&str, &str)] = &[
66    ("Self", "Self_"),
67    ("abstract", "abstract_"),
68    ("as", "as_"),
69    ("become", "become_"),
70    ("box", "box_"),
71    ("break", "break_"),
72    ("const", "const_"),
73    ("continue", "continue_"),
74    ("crate", "crate_"),
75    ("do", "do_"),
76    ("else", "else_"),
77    ("enum", "enum_"),
78    ("extern", "extern_"),
79    ("false", "false_"),
80    ("final", "final_"),
81    ("fn", "fn_"),
82    ("for", "for_"),
83    ("if", "if_"),
84    ("impl", "impl_"),
85    ("in", "in_"),
86    ("let", "let_"),
87    ("loop", "loop_"),
88    ("macro", "macro_"),
89    ("match", "match_"),
90    ("mod", "mod_"),
91    ("move", "move_"),
92    ("mut", "mut_"),
93    ("override", "override_"),
94    ("priv", "priv_"),
95    ("pub", "pub_"),
96    ("ref", "ref_"),
97    ("return", "return_"),
98    ("self", "self_"),
99    ("static", "static_"),
100    ("struct", "struct_"),
101    ("super", "super_"),
102    ("trait", "trait_"),
103    ("true", "true_"),
104    ("try", "try_"),
105    ("type", "type_"),
106    ("typeof", "typeof_"),
107    ("union", "union_"),
108    ("unsafe", "unsafe_"),
109    ("unsized", "unsized_"),
110    ("use", "use_"),
111    ("virtual", "virtual_"),
112    ("where", "where_"),
113    ("while", "while_"),
114    ("yield", "yield_"),
115];
116
117#[cfg(test)]
118mod tests {
119    use super::KEYWORDS;
120
121    #[test]
122    fn verify_keyword_order() {
123        for i in 1..KEYWORDS.len() {
124            assert!(dbg!(KEYWORDS[i - 1].0) < dbg!(KEYWORDS[i].0));
125        }
126    }
127}