xsd_parser/types/
name_builder.rs

1use std::fmt::Display;
2use std::mem::take;
3use std::sync::atomic::Ordering;
4use std::sync::{atomic::AtomicUsize, Arc};
5
6use super::Name;
7
8/// Builder type to construct a [`Name`].
9#[must_use]
10#[derive(Debug, Clone)]
11pub struct NameBuilder {
12    id: Arc<AtomicUsize>,
13    my_id: Option<usize>,
14    with_id: bool,
15    generated: bool,
16
17    name: Option<String>,
18    extension: Option<String>,
19}
20
21impl NameBuilder {
22    /// Create a new [`NameBuilder`] instance.
23    ///
24    /// The passed `id` is used to generate unique ids for unnamed types.
25    pub fn new(id: Arc<AtomicUsize>) -> Self {
26        Self {
27            id,
28            my_id: None,
29            with_id: true,
30            generated: false,
31            name: None,
32            extension: None,
33        }
34    }
35
36    /// Finish the builder and create the [`Name`] instance.
37    #[must_use]
38    pub fn finish(self) -> Name {
39        let Self {
40            id,
41            my_id,
42            with_id,
43            mut generated,
44            name,
45            extension,
46        } = self;
47
48        let mut ret = String::new();
49        if let Some(s) = extension {
50            generated = true;
51            ret.push_str(&Name::unify(&s));
52        }
53
54        if let Some(s) = name {
55            if ret.is_empty() {
56                ret.push_str(&s);
57            } else {
58                ret.push_str(&Name::unify(&s));
59            }
60        }
61
62        if ret.is_empty() {
63            generated = true;
64            ret.push_str("Unnamed");
65        }
66
67        if with_id {
68            generated = true;
69            let id = my_id.unwrap_or_else(|| id.fetch_add(1, Ordering::Relaxed));
70            ret = format!("{ret}{id}");
71        }
72
73        if generated {
74            Name::new_generated(ret)
75        } else {
76            Name::new_named(ret)
77        }
78    }
79
80    /// Wether to add a unique id to the generated name or not.
81    pub fn with_id(mut self, value: bool) -> Self {
82        self.with_id = value;
83
84        self
85    }
86
87    /// Generate the id for the name.
88    ///
89    /// This can be useful if you want to clone the builder to generate multiple names
90    /// with the same id. For example for a field name and corresponding field type.
91    pub fn generate_id(mut self) -> Self {
92        if self.my_id.is_none() {
93            self.my_id = Some(self.id.fetch_add(1, Ordering::Release));
94        }
95
96        self
97    }
98
99    /// Set a unique name.
100    ///
101    /// This will automatically set `with_id` to `false`.
102    pub fn unique_name<T>(mut self, value: T) -> Self
103    where
104        T: Display,
105    {
106        self.name = Some(value.to_string());
107        self.with_id = false;
108
109        self
110    }
111
112    /// Set a shared name.
113    ///
114    /// This will automatically set `with_id` to `true`.
115    pub fn shared_name<T>(mut self, value: T) -> Self
116    where
117        T: Display,
118    {
119        self.name = Some(value.to_string());
120        self.with_id = true;
121
122        self
123    }
124
125    /// Uses the name that is already stored in the builder, or the passed
126    /// `fallback` value if the name was not set yet.
127    pub fn or<T>(self, fallback: T) -> Self
128    where
129        T: NameFallback,
130    {
131        self.or_else(|| fallback)
132    }
133
134    /// Uses the name that is already stored in the builder, or the value that
135    /// is returned by the passed `fallback` closure if the name was not set yet.
136    pub fn or_else<F, T>(mut self, fallback: F) -> Self
137    where
138        F: FnOnce() -> T,
139        T: NameFallback,
140    {
141        if self.name.is_none() {
142            if let Some((generated, name)) = fallback().resolve() {
143                self.name = Some(name);
144                self.with_id = false;
145                self.generated = generated;
146            }
147        }
148
149        self
150    }
151
152    /// Add a extension to the name.
153    ///
154    /// Extensions are added as to the generated name as prefix.
155    pub fn extend<I>(mut self, mut replace: bool, iter: I) -> Self
156    where
157        I: IntoIterator,
158        I::Item: Display,
159    {
160        for s in iter {
161            let s = s.to_string();
162            let s = Name::unify(&s);
163
164            if take(&mut 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        self
174    }
175
176    /// Remove the specified `suffix` from the name and the extension.
177    pub fn remove_suffix(mut self, suffix: &str) -> Self {
178        if let Some(s) = &mut self.name {
179            if let Some(x) = s.strip_suffix(suffix) {
180                *s = x.into();
181            }
182        }
183
184        if let Some(s) = &mut self.extension {
185            if let Some(x) = s.strip_suffix(suffix) {
186                *s = x.into();
187            }
188        }
189
190        self
191    }
192
193    /// Returns `true` if a extension was specified, `false` otherwise.
194    #[inline]
195    #[must_use]
196    pub fn has_extension(&self) -> bool {
197        self.extension.is_some()
198    }
199}
200
201/// Helper trait to define fallback values passed to [`NameBuilder::or`] or
202/// [`NameBuilder::or_else`]
203pub trait NameFallback {
204    /// Create the fallback value.
205    fn resolve(self) -> Option<(bool, String)>;
206}
207
208impl NameFallback for Name {
209    #[inline]
210    fn resolve(self) -> Option<(bool, String)> {
211        (&self).resolve()
212    }
213}
214
215impl NameFallback for &Name {
216    #[inline]
217    fn resolve(self) -> Option<(bool, String)> {
218        Some((self.is_generated(), self.as_str().to_owned()))
219    }
220}
221
222impl NameFallback for Option<&Name> {
223    #[inline]
224    fn resolve(self) -> Option<(bool, String)> {
225        self.and_then(NameFallback::resolve)
226    }
227}
228
229impl NameFallback for Option<Name> {
230    #[inline]
231    fn resolve(self) -> Option<(bool, String)> {
232        self.as_ref().resolve()
233    }
234}
235
236impl NameFallback for &Option<Name> {
237    fn resolve(self) -> Option<(bool, String)> {
238        self.as_ref().resolve()
239    }
240}
241
242impl NameFallback for &String {
243    fn resolve(self) -> Option<(bool, String)> {
244        Some((false, self.to_owned()))
245    }
246}
247
248impl NameFallback for Option<&String> {
249    fn resolve(self) -> Option<(bool, String)> {
250        self.and_then(NameFallback::resolve)
251    }
252}
253
254impl NameFallback for Option<String> {
255    fn resolve(self) -> Option<(bool, String)> {
256        self.as_ref().resolve()
257    }
258}
259
260impl NameFallback for &Option<String> {
261    fn resolve(self) -> Option<(bool, String)> {
262        self.as_ref().resolve()
263    }
264}
265
266impl NameFallback for &str {
267    fn resolve(self) -> Option<(bool, String)> {
268        Some((false, self.to_owned()))
269    }
270}
271
272impl NameFallback for Option<&str> {
273    fn resolve(self) -> Option<(bool, String)> {
274        self.and_then(NameFallback::resolve)
275    }
276}