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    Ident,
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: Ident,
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_: Ident,
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(ident: Ident, type_: Ident, mode: ElementMode, form: FormChoiceType) -> Self {
103        Self {
104            ident,
105            variant: ElementMetaVariant::Type { type_, mode },
106            form,
107            nillable: false,
108            min_occurs: 1,
109            max_occurs: MaxOccurs::Bounded(1),
110            display_name: None,
111            documentation: Vec::new(),
112        }
113    }
114
115    /// Create a new [`ElementMeta`] instance for an `xs:any` element.
116    #[must_use]
117    pub fn any(ident: Ident, meta: AnyMeta) -> Self {
118        Self {
119            ident,
120            variant: ElementMetaVariant::Any { meta },
121            form: FormChoiceType::Unqualified,
122            nillable: false,
123            min_occurs: 1,
124            max_occurs: MaxOccurs::Bounded(1),
125            display_name: None,
126            documentation: Vec::new(),
127        }
128    }
129
130    /// Create a new [`ElementMeta`] instance for a text.
131    #[must_use]
132    pub fn text(ident: Ident) -> Self {
133        Self {
134            ident,
135            variant: ElementMetaVariant::Text,
136            form: FormChoiceType::Unqualified,
137            nillable: false,
138            min_occurs: 1,
139            max_occurs: MaxOccurs::Bounded(1),
140            display_name: None,
141            documentation: Vec::new(),
142        }
143    }
144
145    /// Returns `true` if this element represents a text, `false` otherwise.
146    #[must_use]
147    pub fn is_text(&self) -> bool {
148        matches!(&self.variant, ElementMetaVariant::Text)
149    }
150
151    /// Returns `true` if this element represents an `xs:any` element, `false` otherwise.
152    #[must_use]
153    pub fn is_any(&self) -> bool {
154        matches!(&self.variant, ElementMetaVariant::Any { .. })
155    }
156
157    /// Returns the [`AnyMeta`] if this element is a `xs:any`.
158    #[must_use]
159    pub fn as_any(&self) -> Option<&AnyMeta> {
160        if let ElementMetaVariant::Any { meta } = &self.variant {
161            Some(meta)
162        } else {
163            None
164        }
165    }
166}
167
168impl TypeEq for ElementMeta {
169    fn type_hash<H: Hasher>(&self, hasher: &mut H, types: &MetaTypes) {
170        let Self {
171            ident,
172            variant,
173            form,
174            nillable,
175            min_occurs,
176            max_occurs,
177            display_name,
178            documentation,
179        } = self;
180
181        ident.hash(hasher);
182        variant.type_hash(hasher, types);
183        form.hash(hasher);
184        nillable.hash(hasher);
185        min_occurs.hash(hasher);
186        max_occurs.hash(hasher);
187        display_name.hash(hasher);
188        documentation.hash(hasher);
189    }
190
191    fn type_eq(&self, other: &Self, types: &MetaTypes) -> bool {
192        let Self {
193            ident,
194            variant,
195            form,
196            nillable,
197            min_occurs,
198            max_occurs,
199            display_name,
200            documentation,
201        } = self;
202
203        ident.eq(&other.ident)
204            && variant.type_eq(&other.variant, types)
205            && form.eq(&other.form)
206            && nillable.eq(&other.nillable)
207            && min_occurs.eq(&other.min_occurs)
208            && max_occurs.eq(&other.max_occurs)
209            && display_name.eq(&other.display_name)
210            && documentation.eq(&other.documentation)
211    }
212}
213
214/* ElementsMeta */
215
216impl ElementsMeta {
217    /// Push a new `xs:any` element to the list.
218    ///
219    /// This will update the names of all `xs:any` elements, if more than
220    /// one element was added.
221    pub fn push_any(&mut self, mut el: ElementMeta) {
222        let mut i = 0;
223        for element in &mut self.0 {
224            if element.is_any() && element.ident.name.is_generated() {
225                element.display_name = Some(format!("any_{i}"));
226                i += 1;
227            }
228        }
229
230        el.display_name = Some(if i > 0 {
231            format!("any_{i}")
232        } else {
233            "any".into()
234        });
235
236        self.0.push(el);
237    }
238}
239
240impl Deref for ElementsMeta {
241    type Target = Vec<ElementMeta>;
242
243    fn deref(&self) -> &Self::Target {
244        &self.0
245    }
246}
247
248impl DerefMut for ElementsMeta {
249    fn deref_mut(&mut self) -> &mut Self::Target {
250        &mut self.0
251    }
252}
253
254impl TypeEq for ElementsMeta {
255    fn type_hash<H: Hasher>(&self, hasher: &mut H, types: &MetaTypes) {
256        TypeEq::type_hash_slice(&self.0, hasher, types);
257    }
258
259    fn type_eq(&self, other: &Self, types: &MetaTypes) -> bool {
260        TypeEq::type_eq_iter(self.0.iter(), other.0.iter(), types)
261    }
262}
263
264/* ElementType */
265
266impl TypeEq for ElementMetaVariant {
267    fn type_hash<H: Hasher>(&self, hasher: &mut H, types: &MetaTypes) {
268        match self {
269            Self::Any { meta } => {
270                hasher.write_u8(0);
271                meta.hash(hasher);
272            }
273            Self::Type { type_, mode } => {
274                hasher.write_u8(1);
275                type_.type_hash(hasher, types);
276                mode.hash(hasher);
277            }
278            Self::Text => hasher.write_u8(2),
279        }
280    }
281
282    fn type_eq(&self, other: &Self, types: &MetaTypes) -> bool {
283        match (self, other) {
284            (Self::Any { meta: a }, Self::Any { meta: b }) => a.eq(b),
285            (
286                Self::Type {
287                    type_: type_a,
288                    mode: mode_a,
289                },
290                Self::Type {
291                    type_: type_b,
292                    mode: mode_b,
293                },
294            ) => mode_a.eq(mode_b) && type_a.type_eq(type_b, types),
295            (_, _) => false,
296        }
297    }
298}
299
300/* AnyMeta */
301
302impl Hash for AnyMeta {
303    fn hash<H: Hasher>(&self, hasher: &mut H) {
304        // HACK: We currently only hash the id, because the types from the `xs`
305        // module do not implement `Hash`.
306
307        self.id.hash(hasher);
308    }
309}