xsd_parser/models/
naming.rs

1use 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/// Default name generation and formatting implementation.
12///
13/// This type implements the [`Naming`](NamingTrait) trait that is used for
14/// naming generation and formatting.
15#[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/// Default implementation for the [`NameBuilder`](NameBuilderTrait) trait.
29#[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    /// Create a new [`NameBuilder`] instance.
45    ///
46    /// The passed `id` is used to generate unique ids for unnamed types.
47    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}