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}