xsd_parser/models/meta/
complex.rs1use 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#[derive(Default, Debug, Clone)]
17pub struct GroupMeta {
18 pub is_mixed: bool,
20
21 pub elements: ElementsMeta,
23}
24
25#[derive(Debug, Clone)]
27pub struct ComplexMeta {
28 pub base: Base,
30
31 pub content: Option<Ident>,
34
35 pub min_occurs: MinOccurs,
37
38 pub max_occurs: MaxOccurs,
40
41 pub is_dynamic: bool,
43
44 pub is_mixed: bool,
46
47 pub attributes: AttributesMeta,
49}
50
51impl GroupMeta {
54 #[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
101impl ComplexMeta {
104 #[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 #[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 #[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 #[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 #[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 #[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 #[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}