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, BasicNamespaceListType, NamespaceListType, ProcessContentsType, QnameListAType,
7    QnameListType,
8};
9use crate::schema::{MaxOccurs, MinOccurs};
10use crate::types::{Ident, TypeEq, TypeVariant, 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<BasicNamespaceListType>,
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<BasicNamespaceListType>,
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 [`TypeVariant::Choice`], `false` otherwise.
108    #[must_use]
109    pub fn has_complex_choice_content(&self, types: &Types) -> bool {
110        matches!(
111            self.content
112                .as_ref()
113                .and_then(|ident| types.get_resolved_type(ident))
114                .map(|ty| &ty.variant),
115            Some(TypeVariant::Choice(_))
116        )
117    }
118
119    /// Returns `true` if the content of this complex type information
120    /// is a [`TypeVariant::All`], [`TypeVariant::Choice`] or [`TypeVariant::Sequence`],
121    /// `false` otherwise.
122    #[must_use]
123    pub fn has_complex_content(&self, types: &Types) -> bool {
124        matches!(
125            self.content
126                .as_ref()
127                .and_then(|ident| types.get_resolved_type(ident))
128                .map(|ty| &ty.variant),
129            Some(TypeVariant::All(_) | TypeVariant::Choice(_) | TypeVariant::Sequence(_))
130        )
131    }
132
133    /// Returns `true` if the content of this complex type information
134    /// is a [`TypeVariant::BuildIn`], [`TypeVariant::Union`] or [`TypeVariant::Enumeration`],
135    /// `false` otherwise.
136    #[must_use]
137    pub fn has_simple_content(&self, types: &Types) -> bool {
138        matches!(
139            self.content
140                .as_ref()
141                .and_then(|ident| types.get_resolved_type(ident))
142                .map(|ty| &ty.variant),
143            Some(
144                TypeVariant::Reference(_)
145                    | TypeVariant::BuildIn(_)
146                    | TypeVariant::Union(_)
147                    | TypeVariant::Enumeration(_)
148            )
149        )
150    }
151}
152
153impl Default for ComplexInfo {
154    fn default() -> Self {
155        Self {
156            base: Base::None,
157            content: None,
158            min_occurs: 1,
159            max_occurs: MaxOccurs::Bounded(1),
160            is_dynamic: false,
161            attributes: AttributesInfo::default(),
162            any_attribute: None,
163        }
164    }
165}
166
167impl TypeEq for ComplexInfo {
168    fn type_hash<H: Hasher>(&self, hasher: &mut H, types: &Types) {
169        let Self {
170            base,
171            content,
172            min_occurs,
173            max_occurs,
174            is_dynamic,
175            attributes,
176            any_attribute,
177        } = self;
178
179        base.type_hash(hasher, types);
180        content.type_hash(hasher, types);
181        min_occurs.hash(hasher);
182        max_occurs.hash(hasher);
183        is_dynamic.hash(hasher);
184        attributes.type_hash(hasher, types);
185
186        // HACK: We currently only evaluate if any is set or not, so just hashing
187        // the result from `is_some` does work, but this might break in the future!
188        any_attribute.is_some().hash(hasher);
189    }
190
191    fn type_eq(&self, other: &Self, types: &Types) -> bool {
192        let Self {
193            base,
194            content,
195            min_occurs,
196            max_occurs,
197            is_dynamic,
198            attributes,
199            any_attribute,
200        } = self;
201
202        base.type_eq(&other.base, types)
203            && content.type_eq(&other.content, types)
204            && min_occurs.eq(&other.min_occurs)
205            && max_occurs.eq(&other.max_occurs)
206            && is_dynamic.eq(&other.is_dynamic)
207            && attributes.type_eq(&other.attributes, types)
208            && any_attribute.eq(&other.any_attribute)
209    }
210}