xsd_parser/models/meta/
complex.rs

1//! Contains the [`ComplexMeta`] type information and all related types.
2
3use std::hash::{Hash, Hasher};
4
5use crate::models::{
6    meta::{ElementMetaVariant, ElementMode},
7    schema::{MaxOccurs, MinOccurs},
8    Ident,
9};
10
11use super::{AttributesMeta, Base, ElementsMeta, MetaType, MetaTypeVariant, MetaTypes, TypeEq};
12
13/// Represents a group of elements.
14///
15/// This is usually a `xs:all`, `xs:choice` or `xs:sequence`.
16#[derive(Default, Debug, Clone)]
17pub struct GroupMeta {
18    /// Wether the content of this type is mixed (contains also text) or not.
19    pub is_mixed: bool,
20
21    /// List of elements defined in this group.
22    pub elements: ElementsMeta,
23}
24
25/// Type information that contains data about a complex type.
26#[derive(Debug, Clone)]
27pub struct ComplexMeta {
28    /// Base type of the complex type.
29    pub base: Base,
30
31    /// Content type information of the complex type that contains the actual
32    /// information about the elements that are defined for this type.
33    pub content: Option<Ident>,
34
35    /// Minimum occurrence of this complex types content type.
36    pub min_occurs: MinOccurs,
37
38    /// Maximum occurrence of this complex types content type.
39    pub max_occurs: MaxOccurs,
40
41    /// Whether the type is dynamic or not.
42    pub is_dynamic: bool,
43
44    /// Wether the content of this type is mixed (contains also text) or not.
45    pub is_mixed: bool,
46
47    /// List of attributes defined for this complex type.
48    pub attributes: AttributesMeta,
49}
50
51/* GroupMeta */
52
53impl GroupMeta {
54    /// Returns `true` if this type is emptiable, `false` otherwise.
55    ///
56    /// Emptiable means that the type may not have any element, but a simple
57    /// text value.
58    #[must_use]
59    pub fn is_emptiable(&self, types: &MetaTypes) -> bool {
60        for element in &*self.elements {
61            if element.min_occurs == 0 {
62                continue;
63            }
64
65            match &element.variant {
66                ElementMetaVariant::Text => (),
67                ElementMetaVariant::Any { .. }
68                | ElementMetaVariant::Type {
69                    mode: ElementMode::Element,
70                    ..
71                } => return false,
72                ElementMetaVariant::Type { type_, .. } => {
73                    if let Some(ty) = types.items.get(type_) {
74                        if !ty.is_emptiable(types) {
75                            return false;
76                        }
77                    }
78                }
79            }
80        }
81
82        true
83    }
84}
85
86impl TypeEq for GroupMeta {
87    fn type_hash<H: Hasher>(&self, hasher: &mut H, types: &MetaTypes) {
88        let Self { is_mixed, elements } = self;
89
90        is_mixed.hash(hasher);
91        elements.type_hash(hasher, types);
92    }
93
94    fn type_eq(&self, other: &Self, types: &MetaTypes) -> bool {
95        let Self { is_mixed, elements } = self;
96
97        is_mixed.eq(&other.is_mixed) && elements.type_eq(&other.elements, types)
98    }
99}
100
101/* ComplexMeta */
102
103impl ComplexMeta {
104    /// Get the meta type information of the content fo this complex type.
105    #[must_use]
106    pub fn content_meta<'a>(&'a self, types: &'a MetaTypes) -> Option<&'a MetaType> {
107        self.content
108            .as_ref()
109            .and_then(|ident| types.get_resolved_type(ident))
110    }
111
112    /// Returns `true` if the content of this complex type information
113    /// is a [`MetaTypeVariant::All`], `false` otherwise.
114    #[must_use]
115    pub fn has_complex_all_content(&self, types: &MetaTypes) -> bool {
116        matches!(
117            self.content_meta(types).map(|ty| &ty.variant),
118            Some(MetaTypeVariant::All(_))
119        )
120    }
121
122    /// Returns `true` if the content of this complex type information
123    /// is a [`MetaTypeVariant::Choice`], `false` otherwise.
124    #[must_use]
125    pub fn has_complex_choice_content(&self, types: &MetaTypes) -> bool {
126        matches!(
127            self.content_meta(types).map(|ty| &ty.variant),
128            Some(MetaTypeVariant::Choice(_))
129        )
130    }
131
132    /// Returns `true` if the content of this complex type information
133    /// is a [`MetaTypeVariant::Sequence`], `false` otherwise.
134    #[must_use]
135    pub fn has_complex_sequence_content(&self, types: &MetaTypes) -> bool {
136        matches!(
137            self.content_meta(types).map(|ty| &ty.variant),
138            Some(MetaTypeVariant::Sequence(_))
139        )
140    }
141
142    /// Returns `true` if the content of this complex type information
143    /// is a [`MetaTypeVariant::All`], [`MetaTypeVariant::Choice`] or [`MetaTypeVariant::Sequence`],
144    /// `false` otherwise.
145    #[must_use]
146    pub fn has_complex_content(&self, types: &MetaTypes) -> bool {
147        matches!(
148            self.content_meta(types).map(|ty| &ty.variant),
149            Some(
150                MetaTypeVariant::All(_) | MetaTypeVariant::Choice(_) | MetaTypeVariant::Sequence(_)
151            )
152        )
153    }
154
155    /// Returns `true` if the content of this complex type information
156    /// is a [`MetaTypeVariant::BuildIn`], [`MetaTypeVariant::Union`] or [`MetaTypeVariant::Enumeration`],
157    /// `false` otherwise.
158    #[must_use]
159    pub fn has_simple_content(&self, types: &MetaTypes) -> bool {
160        matches!(
161            self.content_meta(types).map(|ty| &ty.variant),
162            Some(
163                MetaTypeVariant::Reference(_)
164                    | MetaTypeVariant::BuildIn(_)
165                    | MetaTypeVariant::Union(_)
166                    | MetaTypeVariant::Enumeration(_)
167            )
168        )
169    }
170
171    /// Returns `true` if this type is emptiable, `false` otherwise.
172    ///
173    /// Emptiable means that the type may not have any element.
174    #[must_use]
175    pub fn is_emptiable(&self, types: &MetaTypes) -> bool {
176        if self.min_occurs == 0 {
177            return true;
178        }
179
180        self.content
181            .as_ref()
182            .and_then(|ident| types.items.get(ident))
183            .is_none_or(|ty| ty.is_emptiable(types))
184    }
185}
186
187impl Default for ComplexMeta {
188    fn default() -> Self {
189        Self {
190            base: Base::None,
191            content: None,
192            min_occurs: 1,
193            max_occurs: MaxOccurs::Bounded(1),
194            is_dynamic: false,
195            is_mixed: false,
196            attributes: AttributesMeta::default(),
197        }
198    }
199}
200
201impl TypeEq for ComplexMeta {
202    fn type_hash<H: Hasher>(&self, hasher: &mut H, types: &MetaTypes) {
203        let Self {
204            base,
205            content,
206            min_occurs,
207            max_occurs,
208            is_dynamic,
209            is_mixed: mixed_content,
210            attributes,
211        } = self;
212
213        base.type_hash(hasher, types);
214        content.type_hash(hasher, types);
215        min_occurs.hash(hasher);
216        max_occurs.hash(hasher);
217        is_dynamic.hash(hasher);
218        mixed_content.hash(hasher);
219        attributes.type_hash(hasher, types);
220    }
221
222    fn type_eq(&self, other: &Self, types: &MetaTypes) -> bool {
223        let Self {
224            base,
225            content,
226            min_occurs,
227            max_occurs,
228            is_dynamic,
229            is_mixed: mixed_content,
230            attributes,
231        } = self;
232
233        base.type_eq(&other.base, types)
234            && content.type_eq(&other.content, types)
235            && min_occurs.eq(&other.min_occurs)
236            && max_occurs.eq(&other.max_occurs)
237            && is_dynamic.eq(&other.is_dynamic)
238            && mixed_content.eq(&other.is_mixed)
239            && attributes.type_eq(&other.attributes, types)
240    }
241}