xsd_parser/generator/misc.rs
1use std::collections::{BTreeMap, BTreeSet, HashSet};
2use std::ops::Deref;
3
4use bitflags::bitflags;
5use proc_macro2::{Ident as Ident2, TokenStream};
6use quote::quote;
7
8use crate::code::IdentPath;
9use crate::schema::{MaxOccurs, MinOccurs};
10use crate::types::{DynamicInfo, Ident, Type, TypeVariant, Types};
11
12bitflags! {
13 /// Different flags that control what code the [`Generator`](super::Generator)
14 /// is generating.
15 #[derive(Debug, Clone, Copy)]
16 pub struct GeneratorFlags: u32 {
17 /// None of the features are enabled.
18 ///
19 /// # Examples
20 ///
21 /// Consider the following XML schema:
22 /// ```xml
23 #[doc = include_str!("../../tests/generator/generator_flags/schema.xsd")]
24 /// ```
25 ///
26 /// Setting none of the flags will result in the following code:
27 /// ```rust
28 #[doc = include_str!("../../tests/generator/generator_flags/expected/empty.rs")]
29 /// ```
30 const NONE = 0;
31
32 /// The generated code uses modules for the different namespaces.
33 ///
34 /// # Examples
35 ///
36 /// Consider the following XML schema:
37 /// ```xml
38 #[doc = include_str!("../../tests/generator/generator_flags/schema.xsd")]
39 /// ```
40 ///
41 /// Enable the `USE_MODULES` feature only will result in the following code:
42 /// ```rust,ignore
43 #[doc = include_str!("../../tests/generator/generator_flags/expected/use_modules.rs")]
44 /// ```
45 const USE_MODULES = 1 << 0;
46
47 /// The generator flattens the content type of choice types if it does not
48 /// define any element attributes.
49 ///
50 /// # Examples
51 ///
52 /// Consider the following XML schema:
53 /// ```xml
54 #[doc = include_str!("../../tests/generator/generator_flags/schema.xsd")]
55 /// ```
56 ///
57 /// Enable the `FLATTEN_CONTENT` feature only will result in the following code:
58 /// ```rust
59 #[doc = include_str!("../../tests/generator/generator_flags/expected/flatten_content.rs")]
60 /// ```
61 const FLATTEN_CONTENT = Self::FLATTEN_ENUM_CONTENT.bits()
62 | Self::FLATTEN_STRUCT_CONTENT.bits();
63
64 /// The generator flattens the content of enum types if possible.
65 ///
66 /// See [`FLATTEN_CONTENT`](Self::FLATTEN_CONTENT) for details.
67 const FLATTEN_ENUM_CONTENT = 1 << 1;
68
69 /// The generator flattens the content of struct types if possible.
70 ///
71 /// See [`FLATTEN_CONTENT`](Self::FLATTEN_CONTENT) for details.
72 const FLATTEN_STRUCT_CONTENT = 1 << 2;
73 }
74}
75
76bitflags! {
77 /// Flags to tell the [`Generator`](super::Generator) how to deal with boxed
78 /// types.
79 #[derive(Default, Debug, Clone, Copy, Eq, PartialEq)]
80 pub struct BoxFlags: u32 {
81 /// Boxed types will only be used if necessary.
82 ///
83 /// # Examples
84 ///
85 /// Consider the following XML schema:
86 /// ```xml
87 #[doc = include_str!("../../tests/generator/box_flags/schema.xsd")]
88 /// ```
89 ///
90 /// Enable the `AUTO` feature only will result in the following code:
91 /// ```rust
92 #[doc = include_str!("../../tests/generator/box_flags/expected/auto.rs")]
93 /// ```
94 const AUTO = 0;
95
96 /// Elements in a `xs:choice` type will always be boxed.
97 ///
98 /// # Examples
99 ///
100 /// Consider the following XML schema:
101 /// ```xml
102 #[doc = include_str!("../../tests/generator/box_flags/schema.xsd")]
103 /// ```
104 ///
105 /// Enable the `ENUM_ELEMENTS` feature only will result in the following code:
106 /// ```rust
107 #[doc = include_str!("../../tests/generator/box_flags/expected/enum_elements.rs")]
108 /// ```
109 const ENUM_ELEMENTS = 1 << 0;
110
111 /// Elements in a `xs:all` or `xs:sequence` type will always be boxed.
112 ///
113 /// # Examples
114 ///
115 /// Consider the following XML schema:
116 /// ```xml
117 #[doc = include_str!("../../tests/generator/box_flags/schema.xsd")]
118 /// ```
119 ///
120 /// Enable the `STRUCT_ELEMENTS` feature only will result in the following code:
121 /// ```rust
122 #[doc = include_str!("../../tests/generator/box_flags/expected/struct_elements.rs")]
123 /// ```
124 const STRUCT_ELEMENTS = 1 << 1;
125 }
126}
127
128/// Tells the [`Generator`](super::Generator) how to deal with type definitions.
129#[derive(Default, Debug, Clone, Copy, Eq, PartialEq)]
130pub enum TypedefMode {
131 /// The [`Generator`](super::Generator) will automatically detect if a
132 /// new type struct or a simple type definition should be used
133 /// for a [`Reference`](TypeVariant::Reference) type.
134 ///
135 /// Detecting the correct type automatically depends basically on the
136 /// occurrence of the references type. If the target type is only referenced
137 /// exactly once, a type definition is rendered. If a different
138 /// occurrence is used, it is wrapped in a new type struct because usually
139 /// additional code needs to be implemented for such types.
140 ///
141 /// # Examples
142 ///
143 /// Consider the following XML schema:
144 /// ```xml
145 #[doc = include_str!("../../tests/generator/typedef_mode/schema.xsd")]
146 /// ```
147 ///
148 /// If the typedef mode is set to [`TypedefMode::Auto`] the following code is rendered:
149 /// ```rust
150 #[doc = include_str!("../../tests/generator/typedef_mode/expected/auto.rs")]
151 /// ```
152 #[default]
153 Auto,
154
155 /// The [`Generator`](super::Generator) will always use a simple type definition
156 /// for a [`Reference`](TypeVariant::Reference) type.
157 ///
158 /// # Examples
159 ///
160 /// Consider the following XML schema:
161 /// ```xml
162 #[doc = include_str!("../../tests/generator/typedef_mode/schema.xsd")]
163 /// ```
164 ///
165 /// If the typedef mode is set to [`TypedefMode::Typedef`] the following code is rendered:
166 /// ```rust
167 #[doc = include_str!("../../tests/generator/typedef_mode/expected/typedef.rs")]
168 /// ```
169 Typedef,
170
171 /// The [`Generator`](super::Generator) will always use a new type struct
172 /// for a [`Reference`](TypeVariant::Reference) type.
173 ///
174 /// # Examples
175 ///
176 /// Consider the following XML schema:
177 /// ```xml
178 #[doc = include_str!("../../tests/generator/typedef_mode/schema.xsd")]
179 /// ```
180 ///
181 /// If the typedef mode is set to [`TypedefMode::NewType`] the following code is rendered:
182 /// ```rust
183 #[doc = include_str!("../../tests/generator/typedef_mode/expected/new_type.rs")]
184 /// ```
185 NewType,
186}
187
188/// Tells the [`Generator`](super::Generator) how to generate code for the
189/// [`serde`] crate.
190#[derive(Default, Debug, Clone, Copy, Eq, PartialEq)]
191pub enum SerdeSupport {
192 /// No code for the [`serde`] crate is generated.
193 ///
194 /// # Examples
195 ///
196 /// Consider the following XML schema:
197 /// ```xml
198 #[doc = include_str!("../../tests/generator/serde_support/schema.xsd")]
199 /// ```
200 ///
201 /// If the serde support mode is set to [`SerdeSupport::None`] the following code is rendered:
202 /// ```rust
203 #[doc = include_str!("../../tests/generator/serde_support/expected/none.rs")]
204 /// ```
205 #[default]
206 None,
207
208 /// Generates code that can be serialized and deserialized using the
209 /// [`serde`] create in combination with the with [`quick_xml`] crate.
210 ///
211 /// # Examples
212 ///
213 /// Consider the following XML schema:
214 /// ```xml
215 #[doc = include_str!("../../tests/generator/serde_support/schema.xsd")]
216 /// ```
217 ///
218 /// If the serde support mode is set to [`SerdeSupport::QuickXml`] the following code is rendered:
219 /// ```rust
220 #[doc = include_str!("../../tests/generator/serde_support/expected/quick_xml.rs")]
221 /// ```
222 QuickXml,
223
224 /// Generates code that can be serialized and deserialized using the
225 /// [`serde`] create in combination with the with [`serde-xml-rs`](https://docs.rs/serde-xml-rs) crate.
226 ///
227 /// # Examples
228 ///
229 /// Consider the following XML schema:
230 /// ```xml
231 #[doc = include_str!("../../tests/generator/serde_support/schema.xsd")]
232 /// ```
233 ///
234 /// If the serde support mode is set to [`SerdeSupport::SerdeXmlRs`] the following code is rendered:
235 /// ```rust
236 #[doc = include_str!("../../tests/generator/serde_support/expected/serde_xml_rs.rs")]
237 /// ```
238 SerdeXmlRs,
239}
240
241impl SerdeSupport {
242 /// Returns `true` if this is equal to [`SerdeSupport::None`], `false` otherwise.
243 #[must_use]
244 pub fn is_none(&self) -> bool {
245 matches!(self, Self::None)
246 }
247
248 /// Returns `false` if this is equal to [`SerdeSupport::None`], `true` otherwise.
249 #[must_use]
250 pub fn is_some(&self) -> bool {
251 !matches!(self, Self::None)
252 }
253}
254
255#[derive(Default, Debug, Clone, Copy, Eq, PartialEq)]
256pub enum Occurs {
257 #[default]
258 None,
259 Single,
260 Optional,
261 DynamicList,
262 StaticList(usize),
263}
264
265impl Occurs {
266 pub fn from_occurs(min: MinOccurs, max: MaxOccurs) -> Self {
267 match (min, max) {
268 (0, MaxOccurs::Bounded(0)) => Self::None,
269 (1, MaxOccurs::Bounded(1)) => Self::Single,
270 (0, MaxOccurs::Bounded(1)) => Self::Optional,
271 (a, MaxOccurs::Bounded(b)) if a == b => Self::StaticList(a),
272 (_, _) => Self::DynamicList,
273 }
274 }
275
276 pub fn make_type(self, ident: &TokenStream, need_indirection: bool) -> Option<TokenStream> {
277 match self {
278 Self::None => None,
279 Self::Single if need_indirection => Some(quote! { Box<#ident> }),
280 Self::Single => Some(quote! { #ident }),
281 Self::Optional if need_indirection => Some(quote! { Option<Box<#ident>> }),
282 Self::Optional => Some(quote! { Option<#ident> }),
283 Self::DynamicList => Some(quote! { Vec<#ident> }),
284 Self::StaticList(sz) if need_indirection => Some(quote! { [Box<#ident>; #sz] }),
285 Self::StaticList(sz) => Some(quote! { [#ident; #sz] }),
286 }
287 }
288
289 pub fn is_some(&self) -> bool {
290 *self != Self::None
291 }
292
293 pub fn is_direct(&self) -> bool {
294 matches!(self, Self::Single | Self::Optional | Self::StaticList(_))
295 }
296}
297
298#[derive(Default, Debug)]
299pub enum DynTypeTraits {
300 #[default]
301 Auto,
302 Custom(Vec<IdentPath>),
303}
304
305/* PendingType */
306
307#[derive(Debug)]
308pub(super) struct PendingType<'types> {
309 pub ty: &'types Type,
310 pub ident: Ident,
311}
312
313/* TypeRef */
314
315#[derive(Debug)]
316pub(super) struct TypeRef {
317 pub ident: Ident,
318 pub type_ident: Ident2,
319 pub module_ident: Option<Ident2>,
320 pub boxed_elements: HashSet<Ident>,
321}
322
323impl TypeRef {
324 pub(super) fn to_ident_path(&self) -> IdentPath {
325 if self.ident.is_build_in() {
326 IdentPath::from_ident(self.type_ident.clone())
327 } else {
328 IdentPath::from_ident(self.type_ident.clone()).with_path(self.module_ident.clone())
329 }
330 }
331}
332
333/* TraitInfos */
334
335#[derive(Debug)]
336pub(super) struct TraitInfos(BTreeMap<Ident, TraitInfo>);
337
338impl TraitInfos {
339 #[must_use]
340 pub(super) fn new(types: &Types) -> Self {
341 let mut ret = Self(BTreeMap::new());
342
343 for (base_ident, ty) in types.iter() {
344 let TypeVariant::Dynamic(ai) = &ty.variant else {
345 continue;
346 };
347
348 for type_ident in &ai.derived_types {
349 ret.0
350 .entry(type_ident.clone())
351 .or_default()
352 .traits_all
353 .insert(base_ident.clone());
354
355 match types.get_variant(type_ident) {
356 Some(TypeVariant::Dynamic(DynamicInfo {
357 type_: Some(type_ident),
358 ..
359 })) => {
360 ret.0
361 .entry(type_ident.clone())
362 .or_default()
363 .traits_all
364 .insert(base_ident.clone());
365 }
366 Some(TypeVariant::Reference(ri)) if ri.is_single() => {
367 ret.0
368 .entry(ri.type_.clone())
369 .or_default()
370 .traits_all
371 .insert(base_ident.clone());
372 }
373 _ => (),
374 }
375 }
376 }
377
378 for ident in ret.0.keys().cloned().collect::<Vec<_>>() {
379 let mut traits_second_level = BTreeSet::new();
380
381 ret.collect_traits(&ident, 0, &mut traits_second_level);
382
383 let info = ret.0.get_mut(&ident).unwrap();
384 info.traits_direct = info
385 .traits_all
386 .difference(&traits_second_level)
387 .cloned()
388 .collect();
389 }
390
391 ret
392 }
393
394 fn collect_traits(
395 &self,
396 ident: &Ident,
397 depth: usize,
398 traits_second_level: &mut BTreeSet<Ident>,
399 ) {
400 if depth > 1 {
401 traits_second_level.insert(ident.clone());
402 }
403
404 if let Some(info) = self.0.get(ident) {
405 for trait_ in &info.traits_all {
406 self.collect_traits(trait_, depth + 1, traits_second_level);
407 }
408 }
409 }
410}
411
412impl Deref for TraitInfos {
413 type Target = BTreeMap<Ident, TraitInfo>;
414
415 fn deref(&self) -> &Self::Target {
416 &self.0
417 }
418}
419
420/* TraitInfo */
421
422#[derive(Default, Debug)]
423pub(super) struct TraitInfo {
424 pub traits_all: BTreeSet<Ident>,
425 pub traits_direct: BTreeSet<Ident>,
426}