xsd_parser/models/
naming.rs1use std::any::Any;
2use std::sync::{
3 atomic::{AtomicUsize, Ordering},
4 Arc,
5};
6
7use crate::traits::{NameBuilder as NameBuilderTrait, Naming as NamingTrait};
8
9use super::Name;
10
11#[derive(Default, Debug, Clone)]
16pub struct Naming(Arc<AtomicUsize>);
17
18impl NamingTrait for Naming {
19 fn clone_boxed(&self) -> Box<dyn NamingTrait> {
20 Box::new(self.clone())
21 }
22
23 fn builder(&self) -> Box<dyn NameBuilderTrait> {
24 Box::new(NameBuilder::new(self.0.clone(), self.clone_boxed()))
25 }
26}
27
28#[must_use]
30#[derive(Debug)]
31pub struct NameBuilder {
32 id: Arc<AtomicUsize>,
33 my_id: Option<usize>,
34 with_id: bool,
35 generated: bool,
36
37 name: Option<String>,
38 extension: Option<String>,
39
40 naming: Box<dyn NamingTrait>,
41}
42
43impl NameBuilder {
44 pub fn new(id: Arc<AtomicUsize>, naming: Box<dyn NamingTrait>) -> Self {
48 Self {
49 id,
50 my_id: None,
51 with_id: true,
52 generated: false,
53 name: None,
54 extension: None,
55 naming,
56 }
57 }
58}
59
60impl Clone for NameBuilder {
61 fn clone(&self) -> Self {
62 Self {
63 id: self.id.clone(),
64 my_id: self.my_id,
65 with_id: self.with_id,
66 generated: self.generated,
67 name: self.name.clone(),
68 extension: self.extension.clone(),
69 naming: self.naming.clone_boxed(),
70 }
71 }
72}
73
74impl NameBuilderTrait for NameBuilder {
75 fn finish(&self) -> Name {
76 let Self {
77 id,
78 my_id,
79 with_id,
80 mut generated,
81 name,
82 extension,
83 naming,
84 } = self;
85
86 let mut ret = String::new();
87 if let Some(s) = extension {
88 generated = true;
89 ret.push_str(&naming.unify(s));
90 }
91
92 if let Some(s) = name {
93 if ret.is_empty() {
94 ret.push_str(s);
95 } else {
96 ret.push_str(&naming.unify(s));
97 }
98 }
99
100 if ret.is_empty() {
101 generated = true;
102 ret.push_str("Unnamed");
103 }
104
105 if *with_id {
106 generated = true;
107 let id = my_id.unwrap_or_else(|| id.fetch_add(1, Ordering::Relaxed));
108 ret = format!("{ret}{id}");
109 }
110
111 if generated {
112 Name::new_generated(ret)
113 } else {
114 Name::new_named(ret)
115 }
116 }
117
118 fn merge(&mut self, other: &dyn NameBuilderTrait) {
119 let other: &Self = (other as &dyn Any).downcast_ref().unwrap();
120
121 if let Some(name) = other.name.clone() {
122 self.name.get_or_insert(name);
123 self.with_id = other.with_id;
124 self.generated = other.generated;
125
126 if let Some(id) = other.my_id {
127 self.with_id = other.with_id;
128 self.my_id.get_or_insert(id);
129 }
130
131 if let Some(ext) = other.extension.clone() {
132 self.extension.get_or_insert(ext);
133 }
134 }
135 }
136
137 fn clone_boxed(&self) -> Box<dyn NameBuilderTrait> {
138 Box::new(self.clone())
139 }
140
141 fn has_name(&self) -> bool {
142 self.name.is_some()
143 }
144
145 fn has_extension(&self) -> bool {
146 self.extension.is_some()
147 }
148
149 fn set_name(&mut self, name: String) {
150 self.name = Some(name);
151 }
152
153 fn set_with_id(&mut self, value: bool) {
154 self.with_id = value;
155 }
156
157 fn set_generated(&mut self, value: bool) {
158 self.generated = value;
159 }
160
161 fn add_extension(&mut self, replace: bool, extension: String) {
162 let s = self.naming.unify(&extension);
163
164 if replace {
165 self.extension = Some(s);
166 } else if let Some(prefix) = &self.extension {
167 self.extension = Some(format!("{s}{prefix}"));
168 } else {
169 self.extension = Some(s);
170 }
171 }
172
173 fn strip_suffix(&mut self, suffix: &str) {
174 if let Some(s) = &mut self.name {
175 if let Some(x) = s.strip_suffix(suffix) {
176 *s = x.into();
177 }
178 }
179
180 if let Some(s) = &mut self.extension {
181 if let Some(x) = s.strip_suffix(suffix) {
182 *s = x.into();
183 }
184 }
185 }
186
187 fn generate_unique_id(&mut self) {
188 if self.my_id.is_none() {
189 self.my_id = Some(self.id.fetch_add(1, Ordering::Release));
190 }
191 }
192}
193
194#[cfg(test)]
195mod tests {
196 use crate::traits::Naming as _;
197
198 use super::Naming;
199
200 #[test]
201 fn unify() {
202 let naming = Naming::default();
203
204 assert_eq!("_", naming.unify("+"));
205 assert_eq!("FuuBarBaz", naming.unify("Fuu_BAR_BAZ"));
206 assert_eq!("FuuBarBaz", naming.unify("fuu_bar_baz"));
207 assert_eq!("FuuBarBaz", naming.unify("fuu+Bar-BAZ"));
208 }
209}