1use std::borrow::Cow;
4use std::fmt::{Display, Formatter, Result as FmtResult};
5
6use inflector::Inflector;
7
8#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
10pub enum Name {
11 Named(Cow<'static, str>),
13
14 Generated(Cow<'static, str>),
16}
17
18impl Name {
19 #[must_use]
21 pub const fn named(name: &'static str) -> Self {
22 Self::Named(Cow::Borrowed(name))
23 }
24
25 #[must_use]
27 pub const fn generated(name: &'static str) -> Self {
28 Self::Generated(Cow::Borrowed(name))
29 }
30
31 #[must_use]
33 pub fn new_named<T>(name: T) -> Self
34 where
35 T: Into<Cow<'static, str>>,
36 {
37 Self::Named(name.into())
38 }
39
40 #[must_use]
42 pub fn new_generated<T>(name: T) -> Self
43 where
44 T: Into<Cow<'static, str>>,
45 {
46 Self::Generated(name.into())
47 }
48
49 #[must_use]
51 pub fn is_named(&self) -> bool {
52 matches!(self, Self::Named(_))
53 }
54
55 #[must_use]
57 pub fn is_generated(&self) -> bool {
58 matches!(self, Self::Generated { .. })
59 }
60
61 #[must_use]
63 pub fn as_str(&self) -> &str {
64 match self {
65 Self::Named(s) => s,
66 Self::Generated(s) => s,
67 }
68 }
69
70 #[must_use]
72 pub fn as_named_str(&self) -> Option<&str> {
73 match self {
74 Self::Named(s) => Some(s),
75 Self::Generated(_) => None,
76 }
77 }
78
79 #[must_use]
81 pub fn to_type_name(&self) -> String {
82 Self::format_type_name(self.as_str())
83 }
84
85 #[must_use]
87 pub fn to_field_name(&self) -> String {
88 Self::format_field_name(self.as_str())
89 }
90
91 #[must_use]
93 pub fn unify(s: &str) -> String {
94 s.replace(|c: char| c != '_' && !c.is_alphanumeric(), "_")
95 .to_screaming_snake_case()
96 .to_pascal_case()
97 }
98
99 #[must_use]
101 pub fn format_type_name(s: &str) -> String {
102 let name = Name::unify(s).to_pascal_case();
103
104 if name.starts_with(char::is_numeric) {
105 format!("_{name}")
106 } else {
107 name
108 }
109 }
110
111 #[must_use]
113 pub fn format_field_name(s: &str) -> String {
114 let mut name = Name::unify(s).to_snake_case();
115
116 if let Ok(idx) = KEYWORDS.binary_search_by(|(key, _)| key.cmp(&&*name)) {
117 name = KEYWORDS[idx].1.into();
118 }
119
120 if name.starts_with(char::is_numeric) {
121 name = format!("_{name}");
122 }
123
124 name
125 }
126}
127
128impl AsRef<str> for Name {
129 fn as_ref(&self) -> &str {
130 self.as_str()
131 }
132}
133
134impl Display for Name {
135 fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
136 match self {
137 Self::Named(x) => write!(f, "{x}"),
138 Self::Generated(x) => write!(f, "{x}"),
139 }
140 }
141}
142
143impl From<String> for Name {
144 fn from(value: String) -> Self {
145 Self::Named(Cow::Owned(value))
146 }
147}
148
149impl From<&'static str> for Name {
150 fn from(value: &'static str) -> Self {
151 Self::Named(Cow::Borrowed(value))
152 }
153}
154
155const KEYWORDS: &[(&str, &str)] = &[
156 ("abstract", "abstract_"),
157 ("as", "as_"),
158 ("become", "become_"),
159 ("box", "box_"),
160 ("break", "break_"),
161 ("const", "const_"),
162 ("continue", "continue_"),
163 ("crate", "crate_"),
164 ("do", "do_"),
165 ("else", "else_"),
166 ("enum", "enum_"),
167 ("extern", "extern_"),
168 ("false", "false_"),
169 ("final", "final_"),
170 ("fn", "fn_"),
171 ("for", "for_"),
172 ("if", "if_"),
173 ("impl", "impl_"),
174 ("in", "in_"),
175 ("let", "let_"),
176 ("loop", "loop_"),
177 ("macro", "macro_"),
178 ("match", "match_"),
179 ("mod", "mod_"),
180 ("move", "move_"),
181 ("mut", "mut_"),
182 ("override", "override_"),
183 ("priv", "priv_"),
184 ("pub", "pub_"),
185 ("ref", "ref_"),
186 ("return", "return_"),
187 ("self", "self_"),
188 ("Self", "Self_"),
189 ("static", "static_"),
190 ("struct", "struct_"),
191 ("super", "super_"),
192 ("trait", "trait_"),
193 ("true", "true_"),
194 ("try", "try_"),
195 ("type", "type_"),
196 ("typeof", "typeof_"),
197 ("union", "union_"),
198 ("unsafe", "unsafe_"),
199 ("unsized", "unsized_"),
200 ("use", "use_"),
201 ("virtual", "virtual_"),
202 ("where", "where_"),
203 ("while", "while_"),
204 ("yield", "yield_"),
205];