xsd_parser/models/data/
complex.rs

1use std::ops::Deref;
2
3use bitflags::bitflags;
4use proc_macro2::{Ident as Ident2, Literal, TokenStream};
5
6use crate::models::{
7    data::TagName,
8    meta::{AttributeMeta, ElementMeta},
9    schema::{MaxOccurs, MinOccurs},
10    Ident,
11};
12
13use super::{Occurs, PathData};
14
15/// Contains additional information for the rendering process of a
16/// [`MetaTypeVariant::All`](crate::models::meta::MetaTypeVariant::All),
17/// [`MetaTypeVariant::Choice`](crate::models::meta::MetaTypeVariant::Choice),
18/// [`MetaTypeVariant::Sequence`](crate::models::meta::MetaTypeVariant::Sequence)
19/// or [`MetaTypeVariant::ComplexType`](crate::models::meta::MetaTypeVariant::ComplexType)
20/// type.
21///
22/// To simplify the rendering process this recursive type was added to the
23/// generator. It basically boils down to the following:
24///
25///   - A complex type with a `choice` will result in a struct with a enum
26///     content type.
27///   - A complex type with a `all` or `sequence` will result in a struct
28///     with a struct content type.
29///   - A simple `choice` will result in a single enum type.
30///   - A simple `all` or `sequence` will result in a single sequence.
31///
32/// Additional improvements may be applied to the type, to reduce the complexity
33/// of the generated type (for example flattening the content if possible).
34#[derive(Debug)]
35#[allow(clippy::large_enum_variant)]
36pub enum ComplexData<'types> {
37    /// The type represents an enumeration.
38    ///
39    /// This is normally used for `choice` elements.
40    Enum {
41        /// The main type.
42        type_: ComplexDataEnum<'types>,
43
44        /// The content of the main type (if needed).
45        content_type: Option<Box<ComplexData<'types>>>,
46    },
47
48    /// The type represents a struct.
49    ///
50    /// This is normally used for `all`
51    Struct {
52        /// The main type.
53        type_: ComplexDataStruct<'types>,
54
55        /// The content of the main type (if needed).
56        content_type: Option<Box<ComplexData<'types>>>,
57    },
58}
59
60/// Contains basic information for that is shared between [`ComplexDataEnum`]
61/// and [`ComplexDataStruct`].
62#[derive(Debug)]
63#[allow(clippy::struct_excessive_bools)]
64pub struct ComplexBase<'types> {
65    /// Flags set for this type.
66    pub flags: ComplexFlags,
67
68    /// The identifier of the rendered type.
69    pub type_ident: Ident2,
70
71    /// List of traits that needs to be implemented by this type.
72    pub trait_impls: Vec<TokenStream>,
73
74    /// Name of the XML tag of the type (if the type represents an element in the XML).
75    pub tag_name: Option<TagName<'types>>,
76
77    /// Identifier of the serializer for this type.
78    pub serializer_ident: Ident2,
79
80    /// Identifier of the state of the serializer for this type.
81    pub serializer_state_ident: Ident2,
82
83    /// Identifier of the deserializer for this type.
84    pub deserializer_ident: Ident2,
85
86    /// Identifier of the state of the deserializer for this type.
87    pub deserializer_state_ident: Ident2,
88}
89
90/// Represents a rust enum.
91///
92/// Is used as part of the [`ComplexData`].
93#[derive(Debug)]
94pub struct ComplexDataEnum<'types> {
95    /// Basic type information.
96    pub base: ComplexBase<'types>,
97
98    /// List of `xs:element`s or variants contained in this enum
99    pub elements: Vec<ComplexDataElement<'types>>,
100
101    /// Whether any kind of element is allowed in the enum or not
102    ///
103    /// This is only true if no type for `xs:any` element is defined.
104    pub allow_any: bool,
105
106    /// Whether any kind of attribute is allowed in the enum or not
107    ///
108    /// This is only true if no type for `xs:anyAttribute` element is defined.
109    pub allow_any_attribute: bool,
110}
111
112/// Represents a rust struct.
113///
114/// Is used as part of the [`ComplexData`].
115#[derive(Debug)]
116pub struct ComplexDataStruct<'types> {
117    /// Basic type information.
118    pub base: ComplexBase<'types>,
119
120    /// Additional information about the content of the struct.
121    pub mode: StructMode<'types>,
122
123    /// List of `xs:attribute`s contained in this struct.
124    pub attributes: Vec<ComplexDataAttribute<'types>>,
125
126    /// Whether any kind of attribute is allowed in the struct or not
127    ///
128    /// This is only true if no type for `xs:anyAttribute` element is defined.
129    pub allow_any_attribute: bool,
130}
131
132/// Content of a rust struct.
133///
134/// Used by [`ComplexDataStruct`] to tell how the actual content of the struct
135/// should be rendered.
136#[derive(Debug)]
137#[allow(clippy::large_enum_variant)]
138pub enum StructMode<'types> {
139    /// The struct does not contain any `xs:element`s.
140    Empty {
141        /// Whether any kind of element is allowed in the struct or not
142        ///
143        /// This is only true if no type for `xs:any` element is defined.
144        allow_any: bool,
145    },
146
147    /// The content of the struct is another generated type that contains
148    /// the actual data.
149    Content {
150        /// Information about the content of the struct.
151        content: ComplexDataContent<'types>,
152    },
153
154    /// The content of the struct is a `xs:all` group.
155    All {
156        /// List of `xs:element`s inside the group.
157        elements: Vec<ComplexDataElement<'types>>,
158
159        /// Whether any kind of element is allowed in the struct or not
160        ///
161        /// This is only true if no type for `xs:any` element is defined.
162        allow_any: bool,
163    },
164
165    /// The content of the struct is a `xs:sequence` group.
166    Sequence {
167        /// List of `xs:element`s inside the group.
168        elements: Vec<ComplexDataElement<'types>>,
169
170        /// Whether any kind of element is allowed in the struct or not
171        ///
172        /// This is only true if no type for `xs:any` element is defined.
173        allow_any: bool,
174    },
175}
176
177/// Contains details about the content of a struct.
178///
179/// Is used by [`StructMode`] to define the content of a struct.
180#[derive(Debug)]
181pub struct ComplexDataContent<'types> {
182    /// Occurrence of the content within this struct.
183    pub occurs: Occurs,
184
185    /// Type identifier of the content type if this `ComplexDataContent` was
186    /// constructed from a complex type with simple content.
187    pub simple_type: Option<&'types Ident>,
188
189    /// Minimum occurrence.
190    pub min_occurs: MinOccurs,
191
192    /// Maximum occurrence.
193    pub max_occurs: MaxOccurs,
194
195    /// Actual target type of the content.
196    pub target_type: PathData,
197
198    /// Additional attributes that will be added to the element.
199    pub extra_attributes: Vec<TokenStream>,
200}
201
202/// Contains the details of an XML element.
203///
204/// Is used in [`ComplexDataEnum`] or [`StructMode`].
205#[derive(Debug)]
206pub struct ComplexDataElement<'types> {
207    /// Origin of the element
208    pub origin: ComplexDataElementOrigin<'types>,
209
210    /// Occurrence of the element within it's parent type.
211    pub occurs: Occurs,
212
213    /// Name of the element as string.
214    pub s_name: String,
215
216    /// Name of the element as byte string literal.
217    pub b_name: Literal,
218
219    /// Name of the XML tag of the element.
220    pub tag_name: TagName<'types>,
221
222    /// Field identifier of the element.
223    pub field_ident: Ident2,
224
225    /// Variant identifier of the element.
226    pub variant_ident: Ident2,
227
228    /// Actual target type of the element.
229    pub target_type: PathData,
230
231    /// `true` if this element needs some indirection
232    /// (like a `Box` or a `Vec`), `false` otherwise.
233    pub need_indirection: bool,
234
235    /// `true` if the target type of this element is dynamic,
236    /// `false` otherwise.
237    pub target_is_dynamic: bool,
238
239    /// Additional attributes that will be added to the element.
240    pub extra_attributes: Vec<TokenStream>,
241}
242
243/// Origin of a [`ComplexDataElement`].
244#[derive(Debug)]
245pub enum ComplexDataElementOrigin<'types> {
246    /// The element was created from a corresponding [`ElementMeta`]
247    Meta(&'types ElementMeta),
248
249    /// The element was generated as text element.
250    Generated(Box<ElementMeta>),
251}
252
253/// Contains the details of an XML attribute.
254///
255/// Is used in [`ComplexDataStruct`].
256#[derive(Debug)]
257pub struct ComplexDataAttribute<'types> {
258    /// Reference to the original type information.
259    pub meta: &'types AttributeMeta,
260
261    /// Identifier of the attribute.
262    pub ident: Ident2,
263
264    /// Name of the attribute as string.
265    pub s_name: String,
266
267    /// Name of the attribute as byte string literal.
268    pub b_name: Literal,
269
270    /// Name of the attribute inside the XML tag.
271    pub tag_name: TagName<'types>,
272
273    /// `true` if this attribute is optional, `false` otherwise.
274    pub is_option: bool,
275
276    /// The actual target type of the attribute.
277    pub target_type: PathData,
278
279    /// The default value of the attribute.
280    pub default_value: Option<TokenStream>,
281
282    /// Additional attributes that will be added to the attribute.
283    pub extra_attributes: Vec<TokenStream>,
284}
285
286bitflags! {
287    /// Different flags that may be set for a [`ComplexBase`] type.
288    #[derive(Debug, Clone, Copy, Eq, PartialEq)]
289    pub struct ComplexFlags: u32 {
290        /// Whether the type has at least one `xs:any` element or not.
291        const HAS_ANY = 1 << 0;
292
293        /// `true` if the type is a mixed type, `false` otherwise.
294        const IS_MIXED = 1 << 1;
295
296        /// `true` if the type is a complex type, `false` otherwise.
297        const IS_COMPLEX = 1 << 2;
298
299        /// `true/// `true` if the type is dynamic, `false` otherwise.` if the type is dynamic, `false` otherwise.
300        const IS_DYNAMIC = 1 << 3;
301
302        /// `true` if the type is the content type of another complex type.
303        const IS_CONTENT = 1 << 4;
304    }
305}
306
307impl<'types> ComplexBase<'types> {
308    /// Whether the type has at least one `xs:any` element or not.
309    #[must_use]
310    pub fn has_any(&self) -> bool {
311        self.flags.contains(ComplexFlags::HAS_ANY)
312    }
313
314    /// `true` if the type is a mixed type, `false` otherwise.
315    #[must_use]
316    pub fn is_mixed(&self) -> bool {
317        self.flags.contains(ComplexFlags::IS_MIXED)
318    }
319
320    /// `true` if the type is a complex type, `false` otherwise.
321    #[must_use]
322    pub fn is_complex(&self) -> bool {
323        self.flags.contains(ComplexFlags::IS_COMPLEX)
324    }
325
326    /// `true` if the type is dynamic, `false` otherwise.
327    #[must_use]
328    pub fn is_dynamic(&self) -> bool {
329        self.flags.contains(ComplexFlags::IS_DYNAMIC)
330    }
331
332    /// `true` if the type is the content type of another complex type.
333    #[must_use]
334    pub fn is_content(&self) -> bool {
335        self.flags.contains(ComplexFlags::IS_CONTENT)
336    }
337
338    /// Returns the name of the element tag, if type is represented by a XML element.
339    #[must_use]
340    pub fn element_tag(&self) -> Option<&TagName<'types>> {
341        (self.is_complex() && !self.is_dynamic())
342            .then_some(self.tag_name.as_ref())
343            .flatten()
344    }
345
346    /// Returns `true` if this type represents an element, `false` otherwise.
347    #[must_use]
348    pub fn represents_element(&self) -> bool {
349        self.is_complex() && self.tag_name.is_some() && !self.is_dynamic()
350    }
351}
352
353impl<'types> Deref for ComplexDataEnum<'types> {
354    type Target = ComplexBase<'types>;
355
356    fn deref(&self) -> &Self::Target {
357        &self.base
358    }
359}
360
361impl<'types> ComplexDataStruct<'types> {
362    /// Returns `true` if this struct is a unit struct, `false` otherwise.
363    #[must_use]
364    pub fn is_unit_struct(&self) -> bool {
365        matches!(&self.mode, StructMode::Empty { .. }) && !self.has_attributes()
366    }
367
368    /// Returns `true` if this struct has attributes, `false` otherwise.
369    #[must_use]
370    pub fn has_attributes(&self) -> bool {
371        !self.attributes.is_empty()
372    }
373
374    /// Returns `true` if this struct has a content field, `false` otherwise.
375    #[must_use]
376    pub fn has_content(&self) -> bool {
377        match &self.mode {
378            StructMode::All { elements, .. } | StructMode::Sequence { elements, .. } => {
379                !elements.is_empty()
380            }
381            StructMode::Content { .. } => true,
382            StructMode::Empty { .. } => false,
383        }
384    }
385
386    /// Returns the elements (fields) of this struct.
387    #[must_use]
388    pub fn elements(&self) -> &[ComplexDataElement<'_>] {
389        if let StructMode::All { elements, .. } | StructMode::Sequence { elements, .. } = &self.mode
390        {
391            elements
392        } else {
393            &[]
394        }
395    }
396
397    /// Returns `true` if any kind of element is allowed in the struct, `false` otherwise.
398    #[must_use]
399    pub fn allow_any(&self) -> bool {
400        if let StructMode::Empty { allow_any }
401        | StructMode::All { allow_any, .. }
402        | StructMode::Sequence { allow_any, .. } = &self.mode
403        {
404            *allow_any
405        } else {
406            false
407        }
408    }
409
410    /// Returns the content type if this struct has one.
411    #[must_use]
412    pub fn content(&self) -> Option<&ComplexDataContent<'types>> {
413        if let StructMode::Content { content, .. } = &self.mode {
414            Some(content)
415        } else {
416            None
417        }
418    }
419}
420
421impl<'types> Deref for ComplexDataStruct<'types> {
422    type Target = ComplexBase<'types>;
423
424    fn deref(&self) -> &Self::Target {
425        &self.base
426    }
427}
428
429impl ComplexDataContent<'_> {
430    /// Returns `true` if the content is a simple type (e.g. a enum, union,
431    /// string, integer, ...), `false` otherwise.
432    #[must_use]
433    pub fn is_simple(&self) -> bool {
434        self.simple_type.is_some()
435    }
436
437    /// Returns `true` if the content is a complex type (e.g. a sequence, choice,
438    /// all, ...), `false` otherwise.
439    #[must_use]
440    pub fn is_complex(&self) -> bool {
441        self.simple_type.is_none()
442    }
443}
444
445impl ComplexDataElement<'_> {
446    /// Returns the [`ElementMeta`] this element was created for.
447    #[inline]
448    #[must_use]
449    pub fn meta(&self) -> &ElementMeta {
450        match &self.origin {
451            ComplexDataElementOrigin::Generated(meta) => meta,
452            ComplexDataElementOrigin::Meta(meta) => meta,
453        }
454    }
455}
456
457impl ComplexFlags {
458    /// Adds the `other` flags to the current one if `value` is true and return
459    /// the result.
460    #[must_use]
461    pub fn with(mut self, other: ComplexFlags, value: bool) -> Self {
462        self.set(other, value);
463
464        self
465    }
466
467    /// Extracts the `other` flags from the current ones and return them.
468    #[must_use]
469    pub fn extract(&mut self, other: ComplexFlags) -> Self {
470        let ret = self.intersection(other);
471        self.remove(other);
472        ret
473    }
474}