1use std::collections::HashMap;
11
12use crate::ids::*;
13use crate::parser::location::SourceRef;
14
15#[derive(Debug, Clone, Copy, PartialEq, Eq)]
17pub enum CompositionEdgeKind {
18 Include,
19 Import,
20 Redefine,
21 #[cfg(feature = "xsd11")]
22 Override,
23}
24
25#[derive(Debug, Clone)]
36pub struct CompositionEdge {
37 pub source_doc: DocumentId,
38 pub target_doc: Option<DocumentId>,
39 pub resolved_location: String,
41 pub kind: CompositionEdgeKind,
42 pub source: Option<SourceRef>,
44 pub schema_location: String,
46}
47
48#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
54pub enum ComponentKind {
55 SimpleType,
56 ComplexType,
57 Element,
58 Attribute,
59 ModelGroup,
60 AttributeGroup,
61 Notation,
62 IdentityConstraint,
63}
64
65impl ComponentKind {
66 pub fn display_name(self) -> &'static str {
69 match self {
70 ComponentKind::SimpleType => "simple type",
71 ComponentKind::ComplexType => "complex type",
72 ComponentKind::Element => "element",
73 ComponentKind::Attribute => "attribute",
74 ComponentKind::ModelGroup => "model group",
75 ComponentKind::AttributeGroup => "attribute group",
76 ComponentKind::Notation => "notation",
77 ComponentKind::IdentityConstraint => "identity constraint",
78 }
79 }
80}
81
82#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
84pub struct ComponentIdentity {
85 pub kind: ComponentKind,
86 pub name: NameId,
87 pub namespace: Option<NameId>,
88}
89
90#[derive(Debug, Clone, Copy)]
95pub struct ComponentOrigin {
96 pub owner_doc: Option<DocumentId>,
97 pub identity: ComponentIdentity,
98}
99
100#[derive(Debug, Clone, Copy, PartialEq, Eq)]
102pub enum ComponentKey {
103 Type(TypeKey),
104 Element(ElementKey),
105 Attribute(AttributeKey),
106 ModelGroup(ModelGroupKey),
107 AttributeGroup(AttributeGroupKey),
108 Notation(NotationKey),
109 IdentityConstraint(IdentityConstraintKey),
110}
111
112#[derive(Debug, Clone)]
114pub enum CompositionAction {
115 Declared,
117 Included { from_doc: DocumentId },
119 Redefined {
122 from_doc: Option<DocumentId>,
123 replaced: ComponentOrigin,
124 },
125 #[cfg(feature = "xsd11")]
128 Overridden {
129 from_doc: Option<DocumentId>,
130 replaced: ComponentOrigin,
131 },
132}
133
134#[derive(Debug, Clone)]
140pub struct EffectiveComponent {
141 pub key: ComponentKey,
143 pub origin: ComponentOrigin,
145 pub action: CompositionAction,
147}
148
149pub fn record_provenance(
154 effective_components: &mut HashMap<ComponentIdentity, EffectiveComponent>,
155 key: ComponentKey,
156 kind: ComponentKind,
157 namespace: Option<NameId>,
158 name: NameId,
159 acting_doc_id: Option<DocumentId>,
160 action: CompositionAction,
161) {
162 let identity = ComponentIdentity {
163 kind,
164 name,
165 namespace,
166 };
167 let origin = ComponentOrigin {
168 owner_doc: acting_doc_id,
169 identity,
170 };
171 effective_components.insert(
172 identity,
173 EffectiveComponent {
174 key,
175 origin,
176 action,
177 },
178 );
179}
180
181pub fn redefined_action(
183 redefining_doc_id: Option<DocumentId>,
184 kind: ComponentKind,
185 name: NameId,
186 namespace: Option<NameId>,
187 target_doc_id: Option<DocumentId>,
188) -> CompositionAction {
189 let identity = ComponentIdentity {
190 kind,
191 name,
192 namespace,
193 };
194 CompositionAction::Redefined {
195 from_doc: redefining_doc_id,
196 replaced: ComponentOrigin {
197 owner_doc: target_doc_id,
198 identity,
199 },
200 }
201}
202
203#[cfg(feature = "xsd11")]
205pub fn overridden_action(
206 overriding_doc_id: Option<DocumentId>,
207 kind: ComponentKind,
208 name: NameId,
209 namespace: Option<NameId>,
210 target_doc_id: Option<DocumentId>,
211) -> CompositionAction {
212 let identity = ComponentIdentity {
213 kind,
214 name,
215 namespace,
216 };
217 CompositionAction::Overridden {
218 from_doc: overriding_doc_id,
219 replaced: ComponentOrigin {
220 owner_doc: target_doc_id,
221 identity,
222 },
223 }
224}
225
226#[derive(Debug, Default)]
231pub struct DocumentComponentIndex {
232 index: HashMap<ComponentIdentity, ComponentKey>,
233}
234
235impl DocumentComponentIndex {
236 pub fn new() -> Self {
237 Self::default()
238 }
239
240 pub fn insert(&mut self, identity: ComponentIdentity, key: ComponentKey) {
242 self.index.insert(identity, key);
243 }
244
245 fn get(
247 &self,
248 kind: ComponentKind,
249 namespace: Option<NameId>,
250 name: NameId,
251 ) -> Option<&ComponentKey> {
252 self.index.get(&ComponentIdentity {
253 kind,
254 name,
255 namespace,
256 })
257 }
258
259 pub fn lookup_type(&self, namespace: Option<NameId>, name: NameId) -> Option<TypeKey> {
261 self.lookup_simple_type(namespace, name)
262 .map(TypeKey::Simple)
263 .or_else(|| {
264 self.lookup_complex_type(namespace, name)
265 .map(TypeKey::Complex)
266 })
267 }
268
269 pub fn lookup_simple_type(
271 &self,
272 namespace: Option<NameId>,
273 name: NameId,
274 ) -> Option<SimpleTypeKey> {
275 match self.get(ComponentKind::SimpleType, namespace, name) {
276 Some(&ComponentKey::Type(TypeKey::Simple(key))) => Some(key),
277 _ => None,
278 }
279 }
280
281 pub fn lookup_complex_type(
283 &self,
284 namespace: Option<NameId>,
285 name: NameId,
286 ) -> Option<ComplexTypeKey> {
287 match self.get(ComponentKind::ComplexType, namespace, name) {
288 Some(&ComponentKey::Type(TypeKey::Complex(key))) => Some(key),
289 _ => None,
290 }
291 }
292
293 pub fn lookup_element(&self, namespace: Option<NameId>, name: NameId) -> Option<ElementKey> {
295 match self.get(ComponentKind::Element, namespace, name) {
296 Some(&ComponentKey::Element(key)) => Some(key),
297 _ => None,
298 }
299 }
300
301 pub fn lookup_attribute(
303 &self,
304 namespace: Option<NameId>,
305 name: NameId,
306 ) -> Option<AttributeKey> {
307 match self.get(ComponentKind::Attribute, namespace, name) {
308 Some(&ComponentKey::Attribute(key)) => Some(key),
309 _ => None,
310 }
311 }
312
313 pub fn lookup_model_group(
315 &self,
316 namespace: Option<NameId>,
317 name: NameId,
318 ) -> Option<ModelGroupKey> {
319 match self.get(ComponentKind::ModelGroup, namespace, name) {
320 Some(&ComponentKey::ModelGroup(key)) => Some(key),
321 _ => None,
322 }
323 }
324
325 pub fn lookup_attribute_group(
327 &self,
328 namespace: Option<NameId>,
329 name: NameId,
330 ) -> Option<AttributeGroupKey> {
331 match self.get(ComponentKind::AttributeGroup, namespace, name) {
332 Some(&ComponentKey::AttributeGroup(key)) => Some(key),
333 _ => None,
334 }
335 }
336
337 pub fn lookup_notation(&self, namespace: Option<NameId>, name: NameId) -> Option<NotationKey> {
339 match self.get(ComponentKind::Notation, namespace, name) {
340 Some(&ComponentKey::Notation(key)) => Some(key),
341 _ => None,
342 }
343 }
344
345 pub fn is_empty(&self) -> bool {
347 self.index.is_empty()
348 }
349
350 pub fn len(&self) -> usize {
352 self.index.len()
353 }
354
355 pub fn iter(&self) -> impl Iterator<Item = (&ComponentIdentity, &ComponentKey)> {
357 self.index.iter()
358 }
359}
360
361#[cfg(test)]
362mod tests {
363 use super::*;
364
365 #[test]
366 fn test_composition_edge_kind_equality() {
367 assert_eq!(CompositionEdgeKind::Include, CompositionEdgeKind::Include);
368 assert_ne!(CompositionEdgeKind::Include, CompositionEdgeKind::Import);
369 assert_ne!(CompositionEdgeKind::Import, CompositionEdgeKind::Redefine);
370 }
371
372 #[test]
373 fn test_composition_edge_construction() {
374 let edge = CompositionEdge {
375 source_doc: 0,
376 target_doc: Some(1),
377 resolved_location: "/path/to/types.xsd".to_string(),
378 kind: CompositionEdgeKind::Include,
379 source: None,
380 schema_location: "types.xsd".to_string(),
381 };
382 assert_eq!(edge.source_doc, 0);
383 assert_eq!(edge.target_doc, Some(1));
384 assert_eq!(edge.kind, CompositionEdgeKind::Include);
385 assert!(edge.source.is_none());
386 assert_eq!(edge.schema_location, "types.xsd");
387 }
388
389 #[test]
390 fn test_composition_edge_cycle_none_target() {
391 let edge = CompositionEdge {
392 source_doc: 1,
393 target_doc: None,
394 resolved_location: "/path/to/cyclic.xsd".to_string(),
395 kind: CompositionEdgeKind::Include,
396 source: None,
397 schema_location: "cyclic.xsd".to_string(),
398 };
399 assert!(edge.target_doc.is_none());
400 assert_eq!(edge.resolved_location, "/path/to/cyclic.xsd");
401 }
402
403 #[test]
404 fn test_composition_edge_with_source() {
405 use crate::parser::location::{SourceRef, SourceSpan};
406 let edge = CompositionEdge {
407 source_doc: 0,
408 target_doc: Some(1),
409 resolved_location: "/path/to/base.xsd".to_string(),
410 kind: CompositionEdgeKind::Redefine,
411 source: Some(SourceRef::new(0, SourceSpan::new(100, 200))),
412 schema_location: "base.xsd".to_string(),
413 };
414 let src = edge.source.unwrap();
415 assert_eq!(src.doc_id, 0);
416 assert_eq!(src.span.start, 100);
417 }
418
419 #[test]
420 fn test_component_kind_variants() {
421 let kinds = [
422 ComponentKind::SimpleType,
423 ComponentKind::ComplexType,
424 ComponentKind::Element,
425 ComponentKind::Attribute,
426 ComponentKind::ModelGroup,
427 ComponentKind::AttributeGroup,
428 ComponentKind::Notation,
429 ComponentKind::IdentityConstraint,
430 ];
431 for (i, a) in kinds.iter().enumerate() {
433 for (j, b) in kinds.iter().enumerate() {
434 if i == j {
435 assert_eq!(a, b);
436 } else {
437 assert_ne!(a, b);
438 }
439 }
440 }
441 }
442
443 #[test]
444 fn test_component_identity_equality_and_copy() {
445 let id1 = ComponentIdentity {
446 kind: ComponentKind::Element,
447 name: NameId(1),
448 namespace: Some(NameId(2)),
449 };
450 let id2 = id1;
452 assert_eq!(id1, id2);
453
454 let id3 = ComponentIdentity {
455 kind: ComponentKind::Attribute,
456 name: NameId(1),
457 namespace: Some(NameId(2)),
458 };
459 assert_ne!(id1, id3);
460 }
461
462 #[test]
463 fn test_component_origin_construction_and_copy() {
464 let origin = ComponentOrigin {
465 owner_doc: Some(42),
466 identity: ComponentIdentity {
467 kind: ComponentKind::SimpleType,
468 name: NameId(5),
469 namespace: None,
470 },
471 };
472 let origin2 = origin;
474 assert_eq!(origin.owner_doc, Some(42));
475 assert_eq!(origin.owner_doc, origin2.owner_doc);
476 assert_eq!(origin.identity.kind, ComponentKind::SimpleType);
477 assert_eq!(origin.identity.name, NameId(5));
478 assert_eq!(origin.identity.namespace, None);
479 }
480
481 #[cfg(feature = "xsd11")]
482 #[test]
483 fn test_override_edge_kind() {
484 assert_eq!(CompositionEdgeKind::Override, CompositionEdgeKind::Override);
485 assert_ne!(CompositionEdgeKind::Override, CompositionEdgeKind::Include);
486 }
487}