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