xsd_parser/models/naming/
default.rs1use std::any::Any;
2use std::sync::{
3 atomic::{AtomicUsize, Ordering},
4 Arc,
5};
6
7use inflector::Inflector;
8use proc_macro2::Ident as Ident2;
9
10use crate::models::{
11 meta::{MetaType, MetaTypeVariant},
12 schema::MaxOccurs,
13 TypeIdent,
14};
15use crate::traits::{NameBuilder as NameBuilderTrait, Naming as NamingTrait};
16
17use super::Name;
18
19#[derive(Default, Debug, Clone)]
24pub struct Naming(Arc<AtomicUsize>);
25
26impl NamingTrait for Naming {
27 fn clone_boxed(&self) -> Box<dyn NamingTrait> {
28 Box::new(self.clone())
29 }
30
31 fn builder(&self) -> Box<dyn NameBuilderTrait> {
32 Box::new(NameBuilder::new(self.0.clone(), self.clone_boxed()))
33 }
34
35 fn unify(&self, s: &str) -> String {
36 super::unify_string(s)
37 }
38
39 fn make_type_name(&self, postfixes: &[String], ty: &MetaType, ident: &TypeIdent) -> Name {
40 if let MetaTypeVariant::Reference(ti) = &ty.variant {
41 if ident.name.is_generated() && ti.type_.name.is_named() {
42 let s = self.format_type_name(ti.type_.name.as_str());
43
44 if ti.max_occurs > MaxOccurs::Bounded(1) {
45 return Name::new_generated(format!("{s}List"));
46 } else if ti.min_occurs == 0 {
47 return Name::new_generated(format!("{s}Opt"));
48 }
49 }
50 }
51
52 let postfix = postfixes
53 .get(ident.type_ as usize)
54 .map_or("", |s| s.as_str());
55
56 let s = self.format_type_name(ident.name.as_str());
57
58 if s.ends_with(postfix) {
59 ident.name.clone()
60 } else {
61 Name::new_generated(format!("{s}{postfix}"))
62 }
63 }
64
65 fn make_unknown_variant(&self, id: usize) -> Ident2 {
66 super::format_unknown_variant(id)
67 }
68
69 fn format_module_name(&self, s: &str) -> String {
70 let s = self.unify(s).to_snake_case();
71
72 super::format_ident(s)
73 }
74
75 fn format_type_name(&self, s: &str) -> String {
76 let s = self.unify(s);
77
78 super::format_ident(s)
79 }
80
81 fn format_field_name(&self, s: &str) -> String {
82 let s = self.unify(s).to_snake_case();
83
84 super::format_ident(s)
85 }
86
87 fn format_variant_name(&self, s: &str) -> String {
88 let s = self.unify(s);
89
90 super::format_ident(s)
91 }
92
93 fn format_constant_name(&self, s: &str) -> String {
94 let s = self.unify(s).to_screaming_snake_case();
95
96 super::format_ident(s)
97 }
98}
99
100#[must_use]
102#[derive(Debug)]
103pub struct NameBuilder {
104 id: Arc<AtomicUsize>,
105 my_id: Option<usize>,
106 with_id: bool,
107 generated: bool,
108
109 name: Option<String>,
110 extension: Option<String>,
111
112 naming: Box<dyn NamingTrait>,
113}
114
115impl NameBuilder {
116 pub fn new(id: Arc<AtomicUsize>, naming: Box<dyn NamingTrait>) -> Self {
120 Self {
121 id,
122 my_id: None,
123 with_id: true,
124 generated: false,
125 name: None,
126 extension: None,
127 naming,
128 }
129 }
130}
131
132impl Clone for NameBuilder {
133 fn clone(&self) -> Self {
134 Self {
135 id: self.id.clone(),
136 my_id: self.my_id,
137 with_id: self.with_id,
138 generated: self.generated,
139 name: self.name.clone(),
140 extension: self.extension.clone(),
141 naming: self.naming.clone_boxed(),
142 }
143 }
144}
145
146impl NameBuilderTrait for NameBuilder {
147 fn finish(&self) -> Name {
148 let Self {
149 id,
150 my_id,
151 with_id,
152 mut generated,
153 name,
154 extension,
155 naming,
156 } = self;
157
158 let mut ret = String::new();
159 if let Some(s) = extension {
160 generated = true;
161 ret.push_str(&naming.unify(s));
162 }
163
164 if let Some(s) = name {
165 if ret.is_empty() {
166 ret.push_str(s);
167 } else {
168 ret.push_str(&naming.unify(s));
169 }
170 }
171
172 if ret.is_empty() {
173 generated = true;
174 ret.push_str("Unnamed");
175 }
176
177 if *with_id {
178 generated = true;
179 let id = my_id.unwrap_or_else(|| id.fetch_add(1, Ordering::Relaxed));
180 ret = format!("{ret}{id}");
181 }
182
183 if generated {
184 Name::new_generated(ret)
185 } else {
186 Name::new_named(ret)
187 }
188 }
189
190 fn merge(&mut self, other: &dyn NameBuilderTrait) {
191 let other: &Self = (other as &dyn Any).downcast_ref().unwrap();
192
193 if let Some(name) = other.name.clone() {
194 self.name.get_or_insert(name);
195 self.with_id = other.with_id;
196 self.generated = other.generated;
197
198 if let Some(id) = other.my_id {
199 self.with_id = other.with_id;
200 self.my_id.get_or_insert(id);
201 }
202
203 if let Some(ext) = other.extension.clone() {
204 self.extension.get_or_insert(ext);
205 }
206 }
207 }
208
209 fn clone_boxed(&self) -> Box<dyn NameBuilderTrait> {
210 Box::new(self.clone())
211 }
212
213 fn has_name(&self) -> bool {
214 self.name.is_some()
215 }
216
217 fn has_extension(&self) -> bool {
218 self.extension.is_some()
219 }
220
221 fn set_name(&mut self, name: String) {
222 self.name = Some(name);
223 }
224
225 fn set_with_id(&mut self, value: bool) {
226 self.with_id = value;
227 }
228
229 fn set_generated(&mut self, value: bool) {
230 self.generated = value;
231 }
232
233 fn add_extension(&mut self, replace: bool, extension: String) {
234 let s = self.naming.unify(&extension);
235
236 if replace {
237 self.extension = Some(s);
238 } else if let Some(prefix) = &self.extension {
239 self.extension = Some(format!("{s}{prefix}"));
240 } else {
241 self.extension = Some(s);
242 }
243 }
244
245 fn strip_suffix(&mut self, suffix: &str) {
246 if let Some(s) = &mut self.name {
247 if let Some(x) = s.strip_suffix(suffix) {
248 *s = x.into();
249 }
250 }
251
252 if let Some(s) = &mut self.extension {
253 if let Some(x) = s.strip_suffix(suffix) {
254 *s = x.into();
255 }
256 }
257 }
258
259 fn generate_unique_id(&mut self) {
260 if self.my_id.is_none() {
261 self.my_id = Some(self.id.fetch_add(1, Ordering::Release));
262 }
263 }
264
265 fn prepare_type_name(&mut self) {
266 self.strip_suffix("Type");
267 self.strip_suffix("Content");
268 }
269
270 fn prepare_field_name(&mut self) {
271 self.strip_suffix("Type");
272 self.strip_suffix("Content");
273 }
274
275 fn prepare_content_type_name(&mut self) {
276 self.strip_suffix("Type");
277 self.strip_suffix("Content");
278 }
279}
280
281#[cfg(test)]
282mod tests {
283 use crate::traits::Naming as _;
284
285 use super::Naming;
286
287 #[test]
288 fn default_naming() {
289 let naming = Naming::default();
290
291 assert_eq!("_", naming.unify("+"));
292 assert_eq!("FuuBarBaz", naming.unify("Fuu_BAR_BAZ"));
293 assert_eq!("FuuBarBaz", naming.unify("fuu_bar_baz"));
294 assert_eq!("FuuBarBaz", naming.unify("fuu+Bar-BAZ"));
295
296 assert_eq!("QName", naming.unify("QName"));
297 assert_eq!("QName", naming.format_type_name("QName"));
298 assert_eq!("QName", naming.format_variant_name("QName"));
299 assert_eq!("q_name", naming.format_field_name("QName"));
300 }
301}