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}