Skip to main content

xsd_parser/models/data/
complex.rs

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