Skip to main content

xsd_parser/models/meta/
attribute.rs

1//! Contains the [`AttributeMeta`] type information and all related types.
2
3use std::hash::{Hash, Hasher};
4use std::ops::{Deref, DerefMut};
5
6use xsd_parser_types::xml::NamespacesShared;
7
8use crate::models::{
9    meta::{MetaTypes, TypeEq},
10    schema::xs::{
11        FormChoiceType, NamespaceListType, NotNamespaceType, ProcessContentsType, QnameListAType,
12        Use,
13    },
14    AttributeIdent, TypeIdent,
15};
16
17/// Type information that contains data about attribute definitions.
18#[derive(Debug, Clone)]
19pub struct AttributeMeta {
20    /// Identifier of the attribute.
21    pub ident: AttributeIdent,
22
23    /// Type of the attribute.
24    pub variant: AttributeMetaVariant,
25
26    /// Usage of the attribute.
27    pub use_: Use,
28
29    /// The form of this attribute.
30    pub form: FormChoiceType,
31
32    /// Default value of the attribute.
33    pub default: Option<String>,
34
35    /// Name of the attribute to use inside the generated code.
36    pub display_name: Option<String>,
37
38    /// Documentation of the element extracted from `xs:documentation` nodes.
39    pub documentation: Vec<String>,
40
41    /// Namespaces that are currently in scope for this attribute.
42    pub namespaces: Option<NamespacesShared<'static>>,
43}
44
45/// Variant of a [`AttributeMeta`]
46///
47/// Either it's any attribute or a specific type.
48#[derive(Debug, Clone)]
49pub enum AttributeMetaVariant {
50    /// The attribute is a `xs:anyAttribute`.
51    Any(AnyAttributeMeta),
52
53    /// The attribute has a specific type.
54    Type(TypeIdent),
55}
56
57/// Contains information about attributes that may occur in the XML file that
58/// are not explicitly defined by the schema.
59#[allow(missing_docs)]
60#[derive(Debug, Clone, Eq, PartialEq)]
61pub struct AnyAttributeMeta {
62    pub id: Option<String>,
63    pub namespace: Option<NamespaceListType>,
64    pub not_q_name: Option<QnameListAType>,
65    pub not_namespace: Option<NotNamespaceType>,
66    pub process_contents: ProcessContentsType,
67}
68
69/// Type information that represents a list of [`AttributeMeta`] instances.
70#[derive(Default, Debug, Clone)]
71pub struct AttributesMeta(Vec<AttributeMeta>);
72
73/* AttributeMeta */
74
75impl AttributeMeta {
76    /// Create a new [`AttributeMeta`] instance from the passed `name` and `type_`.
77    #[must_use]
78    pub fn new(ident: AttributeIdent, type_: TypeIdent, form: FormChoiceType) -> Self {
79        Self {
80            ident,
81            variant: AttributeMetaVariant::Type(type_),
82            use_: Use::Optional,
83            form,
84            default: None,
85            display_name: None,
86            documentation: Vec::new(),
87            namespaces: None,
88        }
89    }
90
91    /// Create a new [`AttributeMeta`] instance from for `xs:anyAttribute` attributes.
92    #[must_use]
93    pub fn any(ident: AttributeIdent, any: AnyAttributeMeta) -> Self {
94        Self {
95            ident,
96            variant: AttributeMetaVariant::Any(any),
97            use_: Use::Required,
98            form: FormChoiceType::Unqualified,
99            default: None,
100            display_name: None,
101            documentation: Vec::new(),
102            namespaces: None,
103        }
104    }
105
106    /// Set the [`Use`] value of the attribute.
107    #[must_use]
108    pub fn with_use(mut self, use_: Use) -> Self {
109        self.use_ = use_;
110
111        self
112    }
113
114    /// Returns `true` if this attribute represents an `xs:anyAttribute`, `false` otherwise.
115    #[must_use]
116    pub fn is_any(&self) -> bool {
117        matches!(&self.variant, AttributeMetaVariant::Any(_))
118    }
119
120    /// Returns the [`AnyAttributeMeta`] if this attribute is a `xs:anyAttribute`.
121    #[must_use]
122    pub fn as_any(&self) -> Option<&AnyAttributeMeta> {
123        if let AttributeMetaVariant::Any(any) = &self.variant {
124            Some(any)
125        } else {
126            None
127        }
128    }
129}
130
131impl TypeEq for AttributeMeta {
132    fn type_hash<H: Hasher>(&self, hasher: &mut H, types: &MetaTypes) {
133        let Self {
134            ident,
135            variant,
136            use_,
137            form,
138            default,
139            display_name,
140            documentation,
141            namespaces,
142        } = self;
143
144        ident.hash(hasher);
145        variant.type_hash(hasher, types);
146        use_.hash(hasher);
147        form.hash(hasher);
148        default.hash(hasher);
149        display_name.hash(hasher);
150        documentation.hash(hasher);
151        namespaces.hash(hasher);
152    }
153
154    fn type_eq(&self, other: &Self, types: &MetaTypes) -> bool {
155        let Self {
156            ident,
157            variant: type_,
158            use_,
159            form,
160            default,
161            display_name,
162            documentation,
163            namespaces,
164        } = self;
165
166        ident.eq(&other.ident)
167            && type_.type_eq(&other.variant, types)
168            && use_.eq(&other.use_)
169            && form.eq(&other.form)
170            && default.eq(&other.default)
171            && display_name.eq(&other.display_name)
172            && documentation.eq(&other.documentation)
173            && namespaces.eq(&other.namespaces)
174    }
175}
176
177/* AttributesMeta */
178
179impl Deref for AttributesMeta {
180    type Target = Vec<AttributeMeta>;
181
182    fn deref(&self) -> &Self::Target {
183        &self.0
184    }
185}
186
187impl DerefMut for AttributesMeta {
188    fn deref_mut(&mut self) -> &mut Self::Target {
189        &mut self.0
190    }
191}
192
193impl TypeEq for AttributesMeta {
194    fn type_hash<H: Hasher>(&self, hasher: &mut H, types: &MetaTypes) {
195        TypeEq::type_hash_slice(&self.0, hasher, types);
196    }
197
198    fn type_eq(&self, other: &Self, types: &MetaTypes) -> bool {
199        TypeEq::type_eq_iter(self.0.iter(), other.0.iter(), types)
200    }
201}
202
203/* AttributeType */
204
205impl TypeEq for AttributeMetaVariant {
206    fn type_hash<H: Hasher>(&self, hasher: &mut H, types: &MetaTypes) {
207        match self {
208            Self::Any(x) => {
209                hasher.write_u8(0);
210                x.hash(hasher);
211            }
212            Self::Type(x) => {
213                hasher.write_u8(1);
214                x.type_hash(hasher, types);
215            }
216        }
217    }
218
219    fn type_eq(&self, other: &Self, types: &MetaTypes) -> bool {
220        match (self, other) {
221            (Self::Any(a), Self::Any(b)) => a.eq(b),
222            (Self::Type(a), Self::Type(b)) => a.type_eq(b, types),
223            (_, _) => false,
224        }
225    }
226}
227
228/* AnyAttributeMeta */
229
230impl Hash for AnyAttributeMeta {
231    fn hash<H: Hasher>(&self, hasher: &mut H) {
232        // HACK: We currently only hash the id, because the types from the `xs`
233        // module do not implement `Hash`.
234
235        self.id.hash(hasher);
236    }
237}