1use crate::ids::{ElementKey, IdentityConstraintKey, NameId, SimpleTypeKey, TypeKey};
6use crate::parser::location::SourceRef;
7use crate::schema::model::DerivationSet;
8
9#[derive(Debug, Clone, Copy, PartialEq, Eq)]
11pub enum DeclarationScope {
12 Global,
14 Local,
16}
17
18#[derive(Debug, Clone, PartialEq, Eq)]
20pub enum ValueConstraint {
21 Default(String),
23 Fixed(String),
25}
26
27impl ValueConstraint {
28 pub fn value(&self) -> &str {
30 match self {
31 ValueConstraint::Default(v) => v,
32 ValueConstraint::Fixed(v) => v,
33 }
34 }
35
36 pub fn is_fixed(&self) -> bool {
38 matches!(self, ValueConstraint::Fixed(_))
39 }
40}
41
42#[derive(Debug, Clone)]
44pub enum TypeReference {
45 Resolved(TypeKey),
47 Unresolved {
49 namespace: Option<NameId>,
50 local_name: NameId,
51 },
52}
53
54#[derive(Debug, Clone)]
58pub struct ElementDecl {
59 pub name: NameId,
61
62 pub target_namespace: Option<NameId>,
64
65 pub source: Option<SourceRef>,
67
68 pub scope: DeclarationScope,
70
71 pub type_def: Option<TypeReference>,
73
74 pub value_constraint: Option<ValueConstraint>,
76
77 pub nillable: bool,
79
80 pub is_abstract: bool,
82
83 pub substitution_group: Option<ElementRef>,
85
86 pub disallowed_substitutions: DerivationSet,
88
89 pub substitution_group_exclusions: DerivationSet,
91
92 pub identity_constraints: Vec<IdentityConstraintKey>,
94
95 pub id: Option<String>,
97
98 pub type_alternatives: Vec<TypeAlternative>,
100
101 pub form: Option<FormKind>,
103}
104
105#[derive(Debug, Clone)]
107pub enum ElementRef {
108 Resolved(ElementKey),
110 Unresolved {
112 namespace: Option<NameId>,
113 local_name: NameId,
114 },
115}
116
117#[derive(Debug, Clone)]
119pub struct TypeAlternative {
120 pub test: Option<String>,
122 pub type_def: TypeReference,
124 pub source: Option<SourceRef>,
126}
127
128#[derive(Debug, Clone, Copy, PartialEq, Eq)]
130pub enum FormKind {
131 Qualified,
132 Unqualified,
133}
134
135impl ElementDecl {
136 pub fn new_global(name: NameId, target_namespace: Option<NameId>) -> Self {
138 Self {
139 name,
140 target_namespace,
141 source: None,
142 scope: DeclarationScope::Global,
143 type_def: None,
144 value_constraint: None,
145 nillable: false,
146 is_abstract: false,
147 substitution_group: None,
148 disallowed_substitutions: DerivationSet::empty(),
149 substitution_group_exclusions: DerivationSet::empty(),
150 identity_constraints: Vec::new(),
151 id: None,
152 type_alternatives: Vec::new(),
153 form: None,
154 }
155 }
156
157 pub fn new_local(name: NameId, target_namespace: Option<NameId>) -> Self {
159 Self {
160 name,
161 target_namespace,
162 source: None,
163 scope: DeclarationScope::Local,
164 type_def: None,
165 value_constraint: None,
166 nillable: false,
167 is_abstract: false,
168 substitution_group: None,
169 disallowed_substitutions: DerivationSet::empty(),
170 substitution_group_exclusions: DerivationSet::empty(),
171 identity_constraints: Vec::new(),
172 id: None,
173 type_alternatives: Vec::new(),
174 form: None,
175 }
176 }
177
178 pub fn is_global(&self) -> bool {
180 self.scope == DeclarationScope::Global
181 }
182
183 pub fn is_local(&self) -> bool {
185 self.scope == DeclarationScope::Local
186 }
187
188 pub fn is_substitutable(&self) -> bool {
190 !self.is_abstract && self.substitution_group_exclusions.is_empty()
191 }
192}
193
194#[derive(Debug, Clone)]
198pub struct AttributeDecl {
199 pub name: NameId,
201
202 pub target_namespace: Option<NameId>,
204
205 pub source: Option<SourceRef>,
207
208 pub scope: DeclarationScope,
210
211 pub type_def: Option<SimpleTypeReference>,
213
214 pub value_constraint: Option<ValueConstraint>,
216
217 pub id: Option<String>,
219
220 pub form: Option<FormKind>,
222
223 pub inheritable: bool,
225}
226
227#[derive(Debug, Clone)]
229pub enum SimpleTypeReference {
230 Resolved(SimpleTypeKey),
232 BuiltIn(crate::types::simple::BuiltInType),
234 Unresolved {
236 namespace: Option<NameId>,
237 local_name: NameId,
238 },
239}
240
241impl AttributeDecl {
242 pub fn new_global(name: NameId, target_namespace: Option<NameId>) -> Self {
244 Self {
245 name,
246 target_namespace,
247 source: None,
248 scope: DeclarationScope::Global,
249 type_def: None,
250 value_constraint: None,
251 id: None,
252 form: None,
253 inheritable: false,
254 }
255 }
256
257 pub fn new_local(name: NameId, target_namespace: Option<NameId>) -> Self {
259 Self {
260 name,
261 target_namespace,
262 source: None,
263 scope: DeclarationScope::Local,
264 type_def: None,
265 value_constraint: None,
266 id: None,
267 form: None,
268 inheritable: false,
269 }
270 }
271
272 pub fn is_global(&self) -> bool {
274 self.scope == DeclarationScope::Global
275 }
276
277 pub fn is_local(&self) -> bool {
279 self.scope == DeclarationScope::Local
280 }
281
282 pub fn has_default(&self) -> bool {
284 matches!(self.value_constraint, Some(ValueConstraint::Default(_)))
285 }
286
287 pub fn has_fixed(&self) -> bool {
289 matches!(self.value_constraint, Some(ValueConstraint::Fixed(_)))
290 }
291}
292
293#[derive(Debug, Clone)]
297pub struct NotationDecl {
298 pub name: NameId,
300
301 pub target_namespace: Option<NameId>,
303
304 pub public: String,
306
307 pub system: Option<String>,
309
310 pub source: Option<SourceRef>,
312
313 pub id: Option<String>,
315}
316
317impl NotationDecl {
318 pub fn new(name: NameId, public: String) -> Self {
320 Self {
321 name,
322 target_namespace: None,
323 public,
324 system: None,
325 source: None,
326 id: None,
327 }
328 }
329}
330
331#[cfg(test)]
332mod tests {
333 use super::*;
334
335 #[test]
336 fn test_element_decl_global() {
337 let elem = ElementDecl::new_global(NameId(1), Some(NameId(2)));
338 assert!(elem.is_global());
339 assert!(!elem.is_local());
340 assert_eq!(elem.scope, DeclarationScope::Global);
341 }
342
343 #[test]
344 fn test_element_decl_local() {
345 let elem = ElementDecl::new_local(NameId(1), None);
346 assert!(elem.is_local());
347 assert!(!elem.is_global());
348 assert_eq!(elem.scope, DeclarationScope::Local);
349 }
350
351 #[test]
352 fn test_element_substitutable() {
353 let mut elem = ElementDecl::new_global(NameId(1), None);
354 assert!(elem.is_substitutable());
355
356 elem.is_abstract = true;
357 assert!(!elem.is_substitutable());
358 }
359
360 #[test]
361 fn test_attribute_decl_global() {
362 let attr = AttributeDecl::new_global(NameId(1), Some(NameId(2)));
363 assert!(attr.is_global());
364 assert!(!attr.is_local());
365 }
366
367 #[test]
368 fn test_attribute_decl_local() {
369 let attr = AttributeDecl::new_local(NameId(1), None);
370 assert!(attr.is_local());
371 assert!(!attr.is_global());
372 }
373
374 #[test]
375 fn test_value_constraint() {
376 let default_val = ValueConstraint::Default("foo".to_string());
377 assert!(!default_val.is_fixed());
378 assert_eq!(default_val.value(), "foo");
379
380 let fixed_val = ValueConstraint::Fixed("bar".to_string());
381 assert!(fixed_val.is_fixed());
382 assert_eq!(fixed_val.value(), "bar");
383 }
384
385 #[test]
386 fn test_attribute_value_constraint() {
387 let mut attr = AttributeDecl::new_local(NameId(1), None);
388 assert!(!attr.has_default());
389 assert!(!attr.has_fixed());
390
391 attr.value_constraint = Some(ValueConstraint::Default("test".to_string()));
392 assert!(attr.has_default());
393 assert!(!attr.has_fixed());
394
395 attr.value_constraint = Some(ValueConstraint::Fixed("test".to_string()));
396 assert!(!attr.has_default());
397 assert!(attr.has_fixed());
398 }
399
400 #[test]
401 fn test_notation_decl() {
402 let notation = NotationDecl::new(NameId(1), "http://example.com/public".to_string());
403 assert_eq!(notation.name, NameId(1));
404 assert_eq!(notation.public, "http://example.com/public");
405 assert!(notation.system.is_none());
406 }
407}