xsd_parser/types/info/
complex.rs

1//! Contains the [`ComplexInfo`] type information and all related types.
2
3use std::hash::{Hash, Hasher};
4
5use crate::schema::xs::{
6    Annotation, NamespaceListType, NotNamespaceType, ProcessContentsType, QnameListAType,
7    QnameListType,
8};
9use crate::schema::{MaxOccurs, MinOccurs};
10use crate::types::{Ident, Type, TypeEq, Types};
11
12use super::{AttributesInfo, Base, ElementsInfo};
13
14/// Type information that contains data about a complex type.
15#[derive(Debug, Clone)]
16pub struct ComplexInfo {
17    /// Base type of the complex type.
18    pub base: Base,
19
20    /// Content type information of the complex type that contains the actual
21    /// information about the elements that are defined for this type.
22    pub content: Option<Ident>,
23
24    /// Minimum occurrence of this complex types content type.
25    pub min_occurs: MinOccurs,
26
27    /// Maximum occurrence of this complex types content type.
28    pub max_occurs: MaxOccurs,
29
30    /// Whether the type is dynamic or not.
31    pub is_dynamic: bool,
32
33    /// List of attributes defined for this complex type.
34    pub attributes: AttributesInfo,
35
36    /// If this complex type accepts any other attribute, that is not defined by
37    /// this type, this contains the information for these attributes, otherwise
38    /// it is set to `None`.
39    pub any_attribute: Option<AnyAttributeInfo>,
40}
41
42/// Represents a group of elements.
43///
44/// This is usually a `xs:all`, `xs:choice` or `xs:sequence`.
45#[derive(Default, Debug, Clone)]
46pub struct GroupInfo {
47    /// If this group accepts any other element, that is not defined by this group,
48    /// this field contains the information for these elements, otherwise it is
49    /// set to `None`.
50    pub any: Option<AnyInfo>,
51
52    /// List of elements defined in this group.
53    pub elements: ElementsInfo,
54}
55
56/// Contains information about elements that may occur in the XML file that
57/// are not explicitly defined by the schema.
58#[allow(missing_docs)]
59#[derive(Default, Debug, Clone, Eq, PartialEq)]
60pub struct AnyInfo {
61    pub id: Option<String>,
62    pub namespace: Option<NamespaceListType>,
63    pub not_namespace: Option<NotNamespaceType>,
64    pub process_contents: Option<ProcessContentsType>,
65    pub not_q_name: Option<QnameListType>,
66    pub min_occurs: Option<MinOccurs>,
67    pub max_occurs: Option<MaxOccurs>,
68    pub annotation: Option<Annotation>,
69}
70
71/// Contains information about attributes that may occur in the XML file that
72/// are not explicitly defined by the schema.
73#[allow(missing_docs)]
74#[derive(Default, Debug, Clone, Eq, PartialEq)]
75pub struct AnyAttributeInfo {
76    pub id: Option<String>,
77    pub namespace: Option<NamespaceListType>,
78    pub not_namespace: Option<NotNamespaceType>,
79    pub process_contents: Option<ProcessContentsType>,
80    pub not_q_name: Option<QnameListAType>,
81    pub annotation: Option<Annotation>,
82}
83
84/* GroupInfo */
85
86impl TypeEq for GroupInfo {
87    fn type_hash<H: Hasher>(&self, hasher: &mut H, types: &Types) {
88        let Self { any, elements } = self;
89
90        // HACK: We currently only evaluate if any is set or not, so just hashing
91        // the result from `is_some` does work, but this might break in the future!
92        any.is_some().hash(hasher);
93        elements.type_hash(hasher, types);
94    }
95
96    fn type_eq(&self, other: &Self, types: &Types) -> bool {
97        let Self { any, elements } = self;
98
99        any.eq(&other.any) && elements.type_eq(&other.elements, types)
100    }
101}
102
103/* ComplexInfo */
104
105impl ComplexInfo {
106    /// Returns `true` if the content of this complex type information
107    /// is a [`Type::All`], [`Type::Choice`] or [`Type::Sequence`],
108    /// `false` otherwise.
109    #[must_use]
110    pub fn has_complex_content(&self, types: &Types) -> bool {
111        matches!(
112            self.content
113                .as_ref()
114                .and_then(|ident| types.get_resolved(ident)),
115            Some(Type::All(_) | Type::Choice(_) | Type::Sequence(_))
116        )
117    }
118
119    /// Returns `true` if the content of this complex type information
120    /// is a [`Type::BuildIn`], [`Type::Union`] or [`Type::Enumeration`],
121    /// `false` otherwise.
122    #[must_use]
123    pub fn has_simple_content(&self, types: &Types) -> bool {
124        matches!(
125            self.content
126                .as_ref()
127                .and_then(|ident| types.get_resolved(ident)),
128            Some(Type::Reference(_) | Type::BuildIn(_) | Type::Union(_) | Type::Enumeration(_))
129        )
130    }
131}
132
133impl Default for ComplexInfo {
134    fn default() -> Self {
135        Self {
136            base: Base::None,
137            content: None,
138            min_occurs: 1,
139            max_occurs: MaxOccurs::Bounded(1),
140            is_dynamic: false,
141            attributes: AttributesInfo::default(),
142            any_attribute: None,
143        }
144    }
145}
146
147impl TypeEq for ComplexInfo {
148    fn type_hash<H: Hasher>(&self, hasher: &mut H, types: &Types) {
149        let Self {
150            base,
151            content,
152            min_occurs,
153            max_occurs,
154            is_dynamic,
155            attributes,
156            any_attribute,
157        } = self;
158
159        base.type_hash(hasher, types);
160        content.type_hash(hasher, types);
161        min_occurs.hash(hasher);
162        max_occurs.hash(hasher);
163        is_dynamic.hash(hasher);
164        attributes.type_hash(hasher, types);
165
166        // HACK: We currently only evaluate if any is set or not, so just hashing
167        // the result from `is_some` does work, but this might break in the future!
168        any_attribute.is_some().hash(hasher);
169    }
170
171    fn type_eq(&self, other: &Self, types: &Types) -> bool {
172        let Self {
173            base,
174            content,
175            min_occurs,
176            max_occurs,
177            is_dynamic,
178            attributes,
179            any_attribute,
180        } = self;
181
182        base.type_eq(&other.base, types)
183            && content.type_eq(&other.content, types)
184            && min_occurs.eq(&other.min_occurs)
185            && max_occurs.eq(&other.max_occurs)
186            && is_dynamic.eq(&other.is_dynamic)
187            && attributes.type_eq(&other.attributes, types)
188            && any_attribute.eq(&other.any_attribute)
189    }
190}