Skip to main content

xsd_parser/models/meta/
element.rs

1//! Contains the [`ElementMeta`] type information and all related types.
2
3use std::hash::{Hash, Hasher};
4use std::ops::{Deref, DerefMut};
5
6use crate::models::{
7    schema::{
8        xs::{
9            FormChoiceType, NamespaceListType, NotNamespaceType, ProcessContentsType, QnameListType,
10        },
11        MaxOccurs, MinOccurs,
12    },
13    ElementIdent, TypeIdent,
14};
15
16use super::{MetaTypes, TypeEq};
17
18/// Type information that contains data about a element.
19#[derive(Debug, Clone)]
20pub struct ElementMeta {
21    /// Identifier of the element.
22    pub ident: ElementIdent,
23
24    /// Type of the element.
25    pub variant: ElementMetaVariant,
26
27    /// The form of this element.
28    pub form: FormChoiceType,
29
30    /// Wether the element is nillable or not.
31    pub nillable: bool,
32
33    /// Minimum occurrence of the field.
34    pub min_occurs: MinOccurs,
35
36    /// Maximum occurrence of the field.
37    pub max_occurs: MaxOccurs,
38
39    /// Name of the element to use inside the generated code.
40    pub display_name: Option<String>,
41
42    /// Documentation of the element extracted from `xs:documentation` nodes.
43    pub documentation: Vec<String>,
44}
45
46/// Variant of a [`ElementMeta`]
47///
48/// Either it's any element or it has a specific type.
49#[derive(Debug, Clone)]
50pub enum ElementMetaVariant {
51    /// Represents any text value in the XML
52    Text,
53
54    /// The element is a `xs:any`.
55    Any {
56        /// Meta information for the `xs:any` element.
57        meta: AnyMeta,
58    },
59
60    /// The element has a specific type.
61    Type {
62        /// Identifier for the type of the element
63        type_: TypeIdent,
64
65        /// Mode if the element
66        mode: ElementMode,
67    },
68}
69
70/// Contains information about elements that may occur in the XML file that
71/// are not explicitly defined by the schema.
72#[allow(missing_docs)]
73#[derive(Debug, Clone, Eq, PartialEq)]
74pub struct AnyMeta {
75    pub id: Option<String>,
76    pub namespace: Option<NamespaceListType>,
77    pub not_q_name: Option<QnameListType>,
78    pub not_namespace: Option<NotNamespaceType>,
79    pub process_contents: ProcessContentsType,
80}
81
82/// Type information that represents a list of [`ElementMeta`] instances.
83#[derive(Default, Debug, Clone)]
84pub struct ElementsMeta(pub Vec<ElementMeta>);
85
86/// Defines the type of an [`ElementMeta`]
87#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
88pub enum ElementMode {
89    /// Represents an actual XML element.
90    Element,
91
92    /// Represents another group of elements.
93    Group,
94}
95
96/* ElementMeta */
97
98impl ElementMeta {
99    /// Create a new [`ElementMeta`] instance from the passed `name`, `type_`
100    /// and `element_mode`.
101    #[must_use]
102    pub fn new(
103        ident: ElementIdent,
104        type_: TypeIdent,
105        mode: ElementMode,
106        form: FormChoiceType,
107    ) -> Self {
108        Self {
109            ident,
110            variant: ElementMetaVariant::Type { type_, mode },
111            form,
112            nillable: false,
113            min_occurs: 1,
114            max_occurs: MaxOccurs::Bounded(1),
115            display_name: None,
116            documentation: Vec::new(),
117        }
118    }
119
120    /// Create a new [`ElementMeta`] instance for an `xs:any` element.
121    #[must_use]
122    pub fn any(ident: ElementIdent, meta: AnyMeta) -> Self {
123        Self {
124            ident,
125            variant: ElementMetaVariant::Any { meta },
126            form: FormChoiceType::Unqualified,
127            nillable: false,
128            min_occurs: 1,
129            max_occurs: MaxOccurs::Bounded(1),
130            display_name: None,
131            documentation: Vec::new(),
132        }
133    }
134
135    /// Create a new [`ElementMeta`] instance for a text.
136    #[must_use]
137    pub fn text(ident: ElementIdent) -> Self {
138        Self {
139            ident,
140            variant: ElementMetaVariant::Text,
141            form: FormChoiceType::Unqualified,
142            nillable: false,
143            min_occurs: 1,
144            max_occurs: MaxOccurs::Bounded(1),
145            display_name: None,
146            documentation: Vec::new(),
147        }
148    }
149
150    /// Returns `true` if this element represents a text, `false` otherwise.
151    #[must_use]
152    pub fn is_text(&self) -> bool {
153        matches!(&self.variant, ElementMetaVariant::Text)
154    }
155
156    /// Returns `true` if this element represents an `xs:any` element, `false` otherwise.
157    #[must_use]
158    pub fn is_any(&self) -> bool {
159        matches!(&self.variant, ElementMetaVariant::Any { .. })
160    }
161
162    /// Returns the [`AnyMeta`] if this element is a `xs:any`.
163    #[must_use]
164    pub fn as_any(&self) -> Option<&AnyMeta> {
165        if let ElementMetaVariant::Any { meta } = &self.variant {
166            Some(meta)
167        } else {
168            None
169        }
170    }
171}
172
173impl TypeEq for ElementMeta {
174    fn type_hash<H: Hasher>(&self, hasher: &mut H, types: &MetaTypes) {
175        let Self {
176            ident,
177            variant,
178            form,
179            nillable,
180            min_occurs,
181            max_occurs,
182            display_name,
183            documentation,
184        } = self;
185
186        ident.hash(hasher);
187        variant.type_hash(hasher, types);
188        form.hash(hasher);
189        nillable.hash(hasher);
190        min_occurs.hash(hasher);
191        max_occurs.hash(hasher);
192        display_name.hash(hasher);
193        documentation.hash(hasher);
194    }
195
196    fn type_eq(&self, other: &Self, types: &MetaTypes) -> bool {
197        let Self {
198            ident,
199            variant,
200            form,
201            nillable,
202            min_occurs,
203            max_occurs,
204            display_name,
205            documentation,
206        } = self;
207
208        ident.eq(&other.ident)
209            && variant.type_eq(&other.variant, types)
210            && form.eq(&other.form)
211            && nillable.eq(&other.nillable)
212            && min_occurs.eq(&other.min_occurs)
213            && max_occurs.eq(&other.max_occurs)
214            && display_name.eq(&other.display_name)
215            && documentation.eq(&other.documentation)
216    }
217}
218
219/* ElementsMeta */
220
221impl ElementsMeta {
222    /// Push a new `xs:any` element to the list.
223    ///
224    /// This will update the names of all `xs:any` elements, if more than
225    /// one element was added.
226    pub fn push_any(&mut self, mut el: ElementMeta) {
227        let mut i = 0;
228        for element in &mut self.0 {
229            if element.is_any() && element.ident.name.is_generated() {
230                element.display_name = Some(format!("any_{i}"));
231                i += 1;
232            }
233        }
234
235        el.display_name = Some(if i > 0 {
236            format!("any_{i}")
237        } else {
238            "any".into()
239        });
240
241        self.0.push(el);
242    }
243}
244
245impl Deref for ElementsMeta {
246    type Target = Vec<ElementMeta>;
247
248    fn deref(&self) -> &Self::Target {
249        &self.0
250    }
251}
252
253impl DerefMut for ElementsMeta {
254    fn deref_mut(&mut self) -> &mut Self::Target {
255        &mut self.0
256    }
257}
258
259impl TypeEq for ElementsMeta {
260    fn type_hash<H: Hasher>(&self, hasher: &mut H, types: &MetaTypes) {
261        TypeEq::type_hash_slice(&self.0, hasher, types);
262    }
263
264    fn type_eq(&self, other: &Self, types: &MetaTypes) -> bool {
265        TypeEq::type_eq_iter(self.0.iter(), other.0.iter(), types)
266    }
267}
268
269/* ElementType */
270
271impl TypeEq for ElementMetaVariant {
272    fn type_hash<H: Hasher>(&self, hasher: &mut H, types: &MetaTypes) {
273        match self {
274            Self::Any { meta } => {
275                hasher.write_u8(0);
276                meta.hash(hasher);
277            }
278            Self::Type { type_, mode } => {
279                hasher.write_u8(1);
280                type_.type_hash(hasher, types);
281                mode.hash(hasher);
282            }
283            Self::Text => hasher.write_u8(2),
284        }
285    }
286
287    fn type_eq(&self, other: &Self, types: &MetaTypes) -> bool {
288        match (self, other) {
289            (Self::Any { meta: a }, Self::Any { meta: b }) => a.eq(b),
290            (
291                Self::Type {
292                    type_: type_a,
293                    mode: mode_a,
294                },
295                Self::Type {
296                    type_: type_b,
297                    mode: mode_b,
298                },
299            ) => mode_a.eq(mode_b) && type_a.type_eq(type_b, types),
300            (_, _) => false,
301        }
302    }
303}
304
305/* AnyMeta */
306
307impl Hash for AnyMeta {
308    fn hash<H: Hasher>(&self, hasher: &mut H) {
309        // HACK: We currently only hash the id, because the types from the `xs`
310        // module do not implement `Hash`.
311
312        self.id.hash(hasher);
313    }
314}