Skip to main content

xsd_parser/models/naming/
explicit.rs

1use std::any::Any;
2use std::sync::{atomic::AtomicUsize, Arc};
3
4use inflector::Inflector;
5use proc_macro2::Ident as Ident2;
6
7use crate::config::MetaType;
8use crate::traits::{NameBuilder as NameBuilderTrait, Naming as NamingTrait};
9use crate::TypeIdent;
10
11use super::{Name, NameBuilder};
12
13/// A more explicit version of [`Naming`](super::Naming) that does not add or
14/// remove any suffixes or prefixes from the generated name expect the one that
15/// were configured by [`Generator::with_type_postfix`](crate::pipeline::Generator::with_type_postfix).
16///
17/// This may result in repeated string inside the generated names (like
18/// `FooTypeType`), but will reduce naming conflicts in most cases.
19#[derive(Debug, Clone)]
20pub struct ExplicitNaming {
21    id: Arc<AtomicUsize>,
22    unify_names: bool,
23    element_field_postfix: Option<String>,
24    attribute_field_postfix: Option<String>,
25}
26
27impl ExplicitNaming {
28    /// Create a new [`ExplicitNaming`] instance.
29    #[must_use]
30    pub fn new() -> Self {
31        Self::default()
32    }
33
34    /// Set whether to unify names the names for all types or not.
35    ///
36    /// Unifying names means that all names will be expressed as pascal case to
37    /// match the naming convention for types in Rust. This may lead to naming
38    /// conflicts.
39    ///
40    /// Default is `true`.
41    #[must_use]
42    pub fn unify_names(mut self, value: bool) -> Self {
43        self.unify_names = value;
44
45        self
46    }
47
48    /// Set the postfix to add to generated element field names.
49    ///
50    /// This can be useful to avoid naming conflicts between element and attribute fields.
51    #[must_use]
52    pub fn with_element_field_postfix<S: Into<String>>(mut self, postfix: S) -> Self {
53        self.element_field_postfix = Some(postfix.into());
54
55        self
56    }
57
58    /// Set the postfix to add to generated attribute field names.
59    ///
60    /// This can be useful to avoid naming conflicts between element and attribute fields.
61    #[must_use]
62    pub fn with_attribute_field_postfix<S: Into<String>>(mut self, postfix: S) -> Self {
63        self.attribute_field_postfix = Some(postfix.into());
64
65        self
66    }
67}
68
69impl Default for ExplicitNaming {
70    fn default() -> Self {
71        Self {
72            id: Arc::new(AtomicUsize::new(0)),
73            unify_names: true,
74            element_field_postfix: None,
75            attribute_field_postfix: None,
76        }
77    }
78}
79
80impl NamingTrait for ExplicitNaming {
81    fn clone_boxed(&self) -> Box<dyn NamingTrait> {
82        Box::new(self.clone())
83    }
84
85    fn builder(&self) -> Box<dyn NameBuilderTrait> {
86        Box::new(ExplicitNameBuilder::new(
87            self.id.clone(),
88            self.clone_boxed(),
89        ))
90    }
91
92    fn unify(&self, s: &str) -> String {
93        if self.unify_names {
94            super::unify_string(s)
95        } else {
96            s.replace(|c: char| !c.is_alphanumeric(), "_")
97        }
98    }
99
100    fn make_type_name(&self, postfixes: &[String], ty: &MetaType, ident: &TypeIdent) -> Name {
101        let _ty = ty;
102        let postfix = postfixes.get(ident.type_ as usize).map(String::as_str);
103
104        let s = self.format_type_name(ident.name.as_str());
105
106        Name::new_generated(if let Some(postfix) = postfix {
107            format!("{s}{postfix}")
108        } else {
109            s
110        })
111    }
112
113    fn make_unknown_variant(&self, id: usize) -> Ident2 {
114        super::format_unknown_variant(id)
115    }
116
117    fn format_module_name(&self, s: &str) -> String {
118        let s = self.unify(s).to_snake_case();
119
120        super::format_ident(s)
121    }
122
123    fn format_type_name(&self, s: &str) -> String {
124        let s = self.unify(s);
125
126        super::format_ident(s)
127    }
128
129    fn format_field_name(&self, s: &str) -> String {
130        let s = self.unify(s).to_snake_case();
131
132        super::format_ident(s)
133    }
134
135    fn format_variant_name(&self, s: &str) -> String {
136        let s = self.unify(s);
137
138        super::format_ident(s)
139    }
140
141    fn format_constant_name(&self, s: &str) -> String {
142        let s = self.unify(s).to_screaming_snake_case();
143
144        super::format_ident(s)
145    }
146
147    fn format_element_field_name(&self, s: &str) -> String {
148        if let Some(postfix) = &self.element_field_postfix {
149            self.format_field_name(&format!("{s}{postfix}"))
150        } else {
151            self.format_field_name(s)
152        }
153    }
154
155    fn format_attribute_field_name(&self, s: &str) -> String {
156        if let Some(postfix) = &self.attribute_field_postfix {
157            self.format_field_name(&format!("{s}{postfix}"))
158        } else {
159            self.format_field_name(s)
160        }
161    }
162}
163
164/// A more explicit version of [`NameBuilder`] that does not add or remove any
165/// suffixes or prefixes from the generated name. This may lead to duplicated
166/// strings inside the generated name (like `FuuTypeType`), but is will reduce
167/// naming conflicts in most cases.
168#[must_use]
169#[derive(Debug, Clone)]
170pub struct ExplicitNameBuilder(NameBuilder);
171
172impl ExplicitNameBuilder {
173    /// Create a new [`ExplicitNameBuilder`] instance.
174    ///
175    /// The passed `id` is used to generate unique ids for unnamed types.
176    pub fn new(id: Arc<AtomicUsize>, naming: Box<dyn NamingTrait>) -> Self {
177        Self(NameBuilder::new(id, naming))
178    }
179}
180
181impl NameBuilderTrait for ExplicitNameBuilder {
182    #[inline]
183    fn finish(&self) -> Name {
184        self.0.finish()
185    }
186
187    #[inline]
188    fn merge(&mut self, other: &dyn NameBuilderTrait) {
189        let other: &Self = (other as &dyn Any).downcast_ref().unwrap();
190
191        self.0.merge(&other.0);
192    }
193
194    #[inline]
195    fn clone_boxed(&self) -> Box<dyn NameBuilderTrait> {
196        Box::new(self.clone())
197    }
198
199    #[inline]
200    fn has_name(&self) -> bool {
201        self.0.has_name()
202    }
203
204    #[inline]
205    fn has_extension(&self) -> bool {
206        self.0.has_extension()
207    }
208
209    #[inline]
210    fn set_name(&mut self, name: String) {
211        self.0.set_name(name);
212    }
213
214    #[inline]
215    fn set_with_id(&mut self, value: bool) {
216        self.0.set_with_id(value);
217    }
218
219    #[inline]
220    fn set_generated(&mut self, value: bool) {
221        self.0.set_generated(value);
222    }
223
224    #[inline]
225    fn add_extension(&mut self, replace: bool, extension: String) {
226        self.0.add_extension(replace, extension);
227    }
228
229    #[inline]
230    fn strip_suffix(&mut self, suffix: &str) {
231        let _suffix = suffix;
232    }
233
234    fn generate_unique_id(&mut self) {
235        self.0.generate_unique_id();
236    }
237
238    fn prepare_type_name(&mut self) {}
239
240    fn prepare_field_name(&mut self) {}
241
242    fn prepare_content_type_name(&mut self) {}
243}