1use crate::arenas::{
26 ComplexTypeDefData, ElementDeclData, IdentityConstraintData, ResolvedAttributeUse,
27 SimpleTypeDefData,
28};
29use std::collections::{HashMap, HashSet};
30
31use crate::error::{SchemaError, SchemaResult};
32use crate::ids::*;
33use crate::namespace::NameTable;
34use crate::parser::frames::{
35 ComplexContentResult, ElementFrameResult, IdentityKind, IdentityResult, ParticleResult,
36 ParticleTerm, QNameRef, TypeFrameResult, TypeRefResult,
37};
38use crate::parser::location::{SourceMapStorage, SourceRef};
39use crate::schema::model::DerivationSet;
40use crate::schema::SchemaSet;
41
42fn resolve_derivation_default(
48 parsed: Option<DerivationSet>,
49 source: Option<&SourceRef>,
50 schema_set: &SchemaSet,
51 pick_default: impl Fn(&crate::schema::model::SchemaDocument) -> DerivationSet,
52) -> DerivationSet {
53 parsed.unwrap_or_else(|| {
54 source
55 .and_then(|s| {
56 let doc_id = s.schema_defaults_doc.unwrap_or(s.doc_id);
57 schema_set.documents.get(doc_id as usize)
58 })
59 .map(pick_default)
60 .unwrap_or_default()
61 })
62}
63
64fn resolve_block(
65 block: Option<DerivationSet>,
66 source: Option<&SourceRef>,
67 schema_set: &SchemaSet,
68) -> DerivationSet {
69 resolve_derivation_default(block, source, schema_set, |d| d.block_default)
70}
71
72fn resolve_final(
73 final_derivation: Option<DerivationSet>,
74 source: Option<&SourceRef>,
75 schema_set: &SchemaSet,
76) -> DerivationSet {
77 resolve_derivation_default(final_derivation, source, schema_set, |d| d.final_default)
78}
79
80#[derive(Debug, Default)]
82pub struct InlineAssemblyStats {
83 pub element_inline_types: usize,
85 pub attribute_inline_types: usize,
87 pub simple_type_inline_derivations: usize,
89 pub complex_type_inline_derivations: usize,
91 pub model_group_inline_types: usize,
93 pub attribute_group_inline_types: usize,
95 pub complex_type_attribute_inline_types: usize,
97 pub total_inline_types: usize,
99}
100
101#[derive(Debug, Clone, Copy)]
103enum InlineRole {
104 ElementType,
106 AttributeType,
108 SimpleTypeBase,
110 ListItemType,
112 UnionMemberType(usize),
114 ComplexTypeBase,
116 ComplexTypeAttribute(usize),
118 ModelGroupParticle(usize),
120 AttributeGroupAttribute(usize),
122 ContentParticleType(usize),
124 #[cfg(feature = "xsd11")]
126 AlternativeType(usize),
127 SimpleContentInlineType,
130}
131
132#[derive(Debug, Clone, Copy)]
134enum InlineOwner {
135 Element(ElementKey),
136 Attribute(AttributeKey),
137 SimpleType(SimpleTypeKey),
138 ComplexType(ComplexTypeKey),
139 ModelGroup(ModelGroupKey),
140 AttributeGroup(AttributeGroupKey),
141}
142
143struct InlineTypeJob {
145 owner: InlineOwner,
146 role: InlineRole,
147 type_frame: TypeFrameResult,
148 target_namespace: Option<NameId>,
149}
150
151pub fn assemble_inline_types(schema_set: &mut SchemaSet) -> SchemaResult<InlineAssemblyStats> {
159 let mut stats = InlineAssemblyStats::default();
160
161 let mut jobs = collect_inline_type_jobs(schema_set);
163
164 while !jobs.is_empty() {
166 let current_jobs: Vec<_> = std::mem::take(&mut jobs);
167
168 for job in current_jobs {
169 let type_key = assemble_inline_type(schema_set, &job.type_frame, job.target_namespace)?;
170 update_owner(schema_set, &job, type_key, &mut stats)?;
171
172 collect_nested_inline_types(schema_set, type_key, job.target_namespace, &mut jobs);
174 }
175 }
176
177 Ok(stats)
178}
179
180fn collect_inline_type_jobs(schema_set: &SchemaSet) -> Vec<InlineTypeJob> {
182 let mut jobs = Vec::new();
183
184 for (key, elem) in schema_set.arenas.elements.iter() {
186 let target_ns = elem.target_namespace;
187 if let Some(inline_type) = &elem.inline_type {
188 jobs.push(InlineTypeJob {
189 owner: InlineOwner::Element(key),
190 role: InlineRole::ElementType,
191 type_frame: (**inline_type).clone(),
192 target_namespace: target_ns,
193 });
194 }
195 }
196
197 #[cfg(feature = "xsd11")]
199 for (key, elem) in schema_set.arenas.elements.iter() {
200 let target_ns = elem.target_namespace;
201 for (idx, alt) in elem.alternatives.iter().enumerate() {
202 if let Some(inline_type) = &alt.inline_type {
203 jobs.push(InlineTypeJob {
204 owner: InlineOwner::Element(key),
205 role: InlineRole::AlternativeType(idx),
206 type_frame: (**inline_type).clone(),
207 target_namespace: target_ns,
208 });
209 }
210 }
211 }
212
213 for (key, attr) in schema_set.arenas.attributes.iter() {
215 let target_ns = attr.target_namespace;
216 if let Some(inline_type) = &attr.inline_type {
217 jobs.push(InlineTypeJob {
218 owner: InlineOwner::Attribute(key),
219 role: InlineRole::AttributeType,
220 type_frame: TypeFrameResult::Simple(Box::new((**inline_type).clone())),
221 target_namespace: target_ns,
222 });
223 }
224 }
225
226 for (key, simple) in schema_set.arenas.simple_types.iter() {
228 let target_ns = simple.target_namespace;
229
230 if let Some(TypeRefResult::Inline(inline_type)) = &simple.base_type {
232 jobs.push(InlineTypeJob {
233 owner: InlineOwner::SimpleType(key),
234 role: InlineRole::SimpleTypeBase,
235 type_frame: (**inline_type).clone(),
236 target_namespace: target_ns,
237 });
238 }
239
240 if let Some(TypeRefResult::Inline(inline_type)) = &simple.item_type {
242 jobs.push(InlineTypeJob {
243 owner: InlineOwner::SimpleType(key),
244 role: InlineRole::ListItemType,
245 type_frame: (**inline_type).clone(),
246 target_namespace: target_ns,
247 });
248 }
249
250 for (idx, member) in simple.member_types.iter().enumerate() {
252 if let TypeRefResult::Inline(inline_type) = member {
253 jobs.push(InlineTypeJob {
254 owner: InlineOwner::SimpleType(key),
255 role: InlineRole::UnionMemberType(idx),
256 type_frame: (**inline_type).clone(),
257 target_namespace: target_ns,
258 });
259 }
260 }
261 }
262
263 for (key, complex) in schema_set.arenas.complex_types.iter() {
265 let target_ns = complex.target_namespace;
266
267 if let Some(TypeRefResult::Inline(inline_type)) = &complex.base_type {
269 jobs.push(InlineTypeJob {
270 owner: InlineOwner::ComplexType(key),
271 role: InlineRole::ComplexTypeBase,
272 type_frame: (**inline_type).clone(),
273 target_namespace: target_ns,
274 });
275 }
276
277 for (idx, attr_use) in complex.attributes.iter().enumerate() {
279 if let Some(inline_type) = &attr_use.attribute.inline_type {
280 jobs.push(InlineTypeJob {
281 owner: InlineOwner::ComplexType(key),
282 role: InlineRole::ComplexTypeAttribute(idx),
283 type_frame: TypeFrameResult::Simple(Box::new((**inline_type).clone())),
284 target_namespace: target_ns,
285 });
286 }
287 }
288
289 collect_content_inline_types(&complex.content, key, target_ns, &mut jobs);
291 }
292
293 for (key, group) in schema_set.arenas.model_groups.iter() {
295 let target_ns = group.target_namespace;
296 let mut flat_idx = 0;
297 collect_model_group_inline_types_recursive(
298 &group.particles,
299 key,
300 target_ns,
301 &mut flat_idx,
302 &mut jobs,
303 );
304 }
305
306 for (key, group) in schema_set.arenas.attribute_groups.iter() {
308 let target_ns = group.target_namespace;
309
310 for (idx, attr_use) in group.attributes.iter().enumerate() {
311 if let Some(inline_type) = &attr_use.attribute.inline_type {
312 jobs.push(InlineTypeJob {
313 owner: InlineOwner::AttributeGroup(key),
314 role: InlineRole::AttributeGroupAttribute(idx),
315 type_frame: TypeFrameResult::Simple(Box::new((**inline_type).clone())),
316 target_namespace: target_ns,
317 });
318 }
319 }
320 }
321
322 jobs
323}
324
325fn collect_content_inline_types(
327 content: &ComplexContentResult,
328 owner_key: ComplexTypeKey,
329 target_ns: Option<NameId>,
330 jobs: &mut Vec<InlineTypeJob>,
331) {
332 match content {
333 ComplexContentResult::Complex(complex_content) => {
334 if let Some(TypeRefResult::Inline(inline_type)) = &complex_content.base_type {
336 jobs.push(InlineTypeJob {
337 owner: InlineOwner::ComplexType(owner_key),
338 role: InlineRole::ComplexTypeBase,
339 type_frame: (**inline_type).clone(),
340 target_namespace: target_ns,
341 });
342 }
343
344 for (idx, attr_use) in complex_content.attributes.iter().enumerate() {
346 if let Some(inline_type) = &attr_use.attribute.inline_type {
347 jobs.push(InlineTypeJob {
348 owner: InlineOwner::ComplexType(owner_key),
349 role: InlineRole::ComplexTypeAttribute(idx),
350 type_frame: TypeFrameResult::Simple(Box::new((**inline_type).clone())),
351 target_namespace: target_ns,
352 });
353 }
354 }
355
356 if let Some(particle) = &complex_content.particle {
358 collect_particle_inline_types(particle, owner_key, target_ns, jobs);
359 }
360 }
361 ComplexContentResult::Simple(simple_content) => {
362 if let Some(TypeRefResult::Inline(inline_type)) = &simple_content.base_type {
364 jobs.push(InlineTypeJob {
365 owner: InlineOwner::ComplexType(owner_key),
366 role: InlineRole::ComplexTypeBase,
367 type_frame: (**inline_type).clone(),
368 target_namespace: target_ns,
369 });
370 }
371
372 for (idx, attr_use) in simple_content.attributes.iter().enumerate() {
374 if let Some(inline_type) = &attr_use.attribute.inline_type {
375 jobs.push(InlineTypeJob {
376 owner: InlineOwner::ComplexType(owner_key),
377 role: InlineRole::ComplexTypeAttribute(idx),
378 type_frame: TypeFrameResult::Simple(Box::new((**inline_type).clone())),
379 target_namespace: target_ns,
380 });
381 }
382 }
383
384 if let Some(inline_st) = &simple_content.content_type {
387 jobs.push(InlineTypeJob {
388 owner: InlineOwner::ComplexType(owner_key),
389 role: InlineRole::SimpleContentInlineType,
390 type_frame: TypeFrameResult::Simple(Box::new((**inline_st).clone())),
391 target_namespace: target_ns,
392 });
393 }
394 }
395 ComplexContentResult::Empty => {}
396 }
397}
398
399fn collect_particle_inline_types(
401 particle: &ParticleResult,
402 owner_key: ComplexTypeKey,
403 target_ns: Option<NameId>,
404 jobs: &mut Vec<InlineTypeJob>,
405) {
406 if let ParticleTerm::Group(group_def) = &particle.term {
407 let mut flat_idx = 0;
408 collect_group_elements_recursive(
409 &group_def.particles,
410 owner_key,
411 target_ns,
412 &mut flat_idx,
413 jobs,
414 );
415 }
416}
417
418fn collect_group_elements_recursive(
420 particles: &[ParticleResult],
421 owner_key: ComplexTypeKey,
422 target_ns: Option<NameId>,
423 flat_idx: &mut usize,
424 jobs: &mut Vec<InlineTypeJob>,
425) {
426 for particle in particles {
427 match &particle.term {
428 ParticleTerm::Element(elem) => {
429 if let Some(inline_type) = &elem.inline_type {
430 jobs.push(InlineTypeJob {
431 owner: InlineOwner::ComplexType(owner_key),
432 role: InlineRole::ContentParticleType(*flat_idx),
433 type_frame: (**inline_type).clone(),
434 target_namespace: target_ns,
435 });
436 }
437 *flat_idx += 1;
438 }
439 ParticleTerm::Group(group_def) if group_def.ref_name.is_none() => {
440 collect_group_elements_recursive(
442 &group_def.particles,
443 owner_key,
444 target_ns,
445 flat_idx,
446 jobs,
447 );
448 }
449 _ => {} }
451 }
452}
453
454fn collect_model_group_inline_types_recursive(
457 particles: &[ParticleResult],
458 owner_key: ModelGroupKey,
459 target_ns: Option<NameId>,
460 flat_idx: &mut usize,
461 jobs: &mut Vec<InlineTypeJob>,
462) {
463 for particle in particles {
464 match &particle.term {
465 ParticleTerm::Element(elem) => {
466 if let Some(inline_type) = &elem.inline_type {
467 jobs.push(InlineTypeJob {
468 owner: InlineOwner::ModelGroup(owner_key),
469 role: InlineRole::ModelGroupParticle(*flat_idx),
470 type_frame: (**inline_type).clone(),
471 target_namespace: target_ns,
472 });
473 }
474 *flat_idx += 1;
475 }
476 ParticleTerm::Group(group_def) if group_def.ref_name.is_none() => {
477 collect_model_group_inline_types_recursive(
479 &group_def.particles,
480 owner_key,
481 target_ns,
482 flat_idx,
483 jobs,
484 );
485 }
486 _ => {} }
488 }
489}
490
491struct ContentParticleElementJob {
493 complex_type_key: ComplexTypeKey,
494 flat_idx: usize,
495 elem: ElementFrameResult,
496 target_namespace: Option<NameId>,
497}
498
499fn collect_content_particle_elements_recursive(
501 particles: &[ParticleResult],
502 complex_type_key: ComplexTypeKey,
503 target_ns: Option<NameId>,
504 flat_idx: &mut usize,
505 jobs: &mut Vec<ContentParticleElementJob>,
506) {
507 for particle in particles {
508 match &particle.term {
509 ParticleTerm::Element(elem) if elem.ref_name.is_none() => {
510 jobs.push(ContentParticleElementJob {
511 complex_type_key,
512 flat_idx: *flat_idx,
513 elem: elem.clone(),
514 target_namespace: target_ns,
515 });
516 *flat_idx += 1;
517 }
518 ParticleTerm::Element(_) => {
519 *flat_idx += 1;
521 }
522 ParticleTerm::Group(group_def) if group_def.ref_name.is_none() => {
523 collect_content_particle_elements_recursive(
524 &group_def.particles,
525 complex_type_key,
526 target_ns,
527 flat_idx,
528 jobs,
529 );
530 }
531 _ => {} }
533 }
534}
535
536fn check_keyref_target(
538 ic: &IdentityResult,
539 target_kind: IdentityKind,
540 target_field_count: usize,
541 refer_name: NameId,
542 name_table: &NameTable,
543 source_maps: &SourceMapStorage,
544) -> SchemaResult<()> {
545 if target_kind == IdentityKind::Keyref {
546 let ic_name = name_table.resolve_ref(ic.name);
547 let refer_name_str = name_table.resolve_ref(refer_name);
548 let location = ic.source.as_ref().and_then(|s| source_maps.locate(s));
549 return Err(SchemaError::structural(
550 "src-identity-constraint",
551 format!(
552 "Keyref '{}': refer target '{}' is a keyref, not a key or unique",
553 ic_name, refer_name_str
554 ),
555 location,
556 ));
557 }
558 if ic.fields.len() != target_field_count {
559 let ic_name = name_table.resolve_ref(ic.name);
560 let refer_name_str = name_table.resolve_ref(refer_name);
561 let location = ic.source.as_ref().and_then(|s| source_maps.locate(s));
562 return Err(SchemaError::structural(
563 "src-identity-constraint",
564 format!(
565 "Keyref '{}': has {} field(s) but refer target '{}' has {} field(s)",
566 ic_name,
567 ic.fields.len(),
568 refer_name_str,
569 target_field_count
570 ),
571 location,
572 ));
573 }
574 Ok(())
575}
576
577pub(crate) fn resolve_ic_ref(
595 kind: IdentityKind,
596 ref_name: &QNameRef,
597 source: Option<&SourceRef>,
598 target_namespace: Option<NameId>,
599 schema_set: &crate::schema::SchemaSet,
600) -> crate::error::SchemaResult<IdentityConstraintKey> {
601 let ref_ns = ref_name.namespace.or(target_namespace);
602 let ref_local = ref_name.local_name;
603
604 crate::schema::resolver::check_namespace_visible_ns(
608 schema_set,
609 ref_ns,
610 ref_local,
611 source,
612 "Identity constraint",
613 )?;
614
615 let target_key = schema_set
617 .namespaces
618 .get(&ref_ns)
619 .and_then(|nt| nt.identity_constraints.get(&ref_local))
620 .copied();
621
622 let target_key = match target_key {
623 Some(k) => k,
624 None => {
625 let mut found = None;
627 for (key, ic_data) in &schema_set.arenas.identity_constraints {
628 if ic_data.name != ref_local {
629 continue;
630 }
631 let ic_ns = ic_data
632 .source
633 .as_ref()
634 .and_then(|s| schema_set.documents.get(s.doc_id as usize))
635 .and_then(|d| d.target_namespace);
636 if ic_ns == ref_ns {
637 found = Some(key);
638 break;
639 }
640 }
641 found.ok_or_else(|| {
642 let ref_display = crate::schema::resolver::format_resolved_qname(
643 &schema_set.name_table,
644 ref_ns,
645 ref_local,
646 );
647 let location = source.and_then(|s| schema_set.source_maps.locate(s));
648 crate::error::SchemaError::structural(
649 "src-resolve",
650 format!("Identity constraint ref target '{}' not found", ref_display),
651 location,
652 )
653 })?
654 }
655 };
656
657 let target = &schema_set.arenas.identity_constraints[target_key];
659 if target.kind != kind {
660 let ref_display = crate::schema::resolver::format_resolved_qname(
661 &schema_set.name_table,
662 ref_ns,
663 ref_local,
664 );
665 let location = source.and_then(|s| schema_set.source_maps.locate(s));
666 return Err(crate::error::SchemaError::structural(
667 "src-identity-constraint.5",
668 format!(
669 "Identity constraint ref '{}': referenced constraint is {:?} but expected {:?}",
670 ref_display, target.kind, kind
671 ),
672 location,
673 ));
674 }
675
676 Ok(target_key)
677}
678
679pub(crate) fn validate_keyref_refers(
680 identity_constraints: &[IdentityResult],
681 target_namespace: Option<NameId>,
682 name_table: &NameTable,
683 source_maps: &SourceMapStorage,
684 ic_arena: &slotmap::SlotMap<IdentityConstraintKey, IdentityConstraintData>,
685 documents: &[crate::schema::model::SchemaDocument],
686) -> SchemaResult<()> {
687 for ic in identity_constraints {
688 if ic.kind != IdentityKind::Keyref {
689 continue;
690 }
691 if let Some(refer) = &ic.refer {
692 let refer_name = refer.local_name;
693 let refer_ns = refer.namespace;
694 let target = identity_constraints.iter().find(|other| {
696 other.name == refer_name && (refer_ns.is_none() || refer_ns == target_namespace)
697 });
698 match target {
699 None => {
700 let effective_refer_ns = refer_ns.or(target_namespace);
705 let global_target = ic_arena.values().find(|ic_data| {
706 if ic_data.name != refer_name {
707 return false;
708 }
709 let ic_ns = match ic_data
717 .source
718 .as_ref()
719 .map(|s| documents.get(s.doc_id as usize))
720 {
721 Some(Some(d)) => d.target_namespace,
722 Some(None) => target_namespace,
723 None => None,
724 };
725 effective_refer_ns == ic_ns
726 });
727 match global_target {
728 Some(target_data) => {
729 check_keyref_target(
730 ic,
731 target_data.kind,
732 target_data.fields.len(),
733 refer_name,
734 name_table,
735 source_maps,
736 )?;
737 }
738 None => {
739 let ic_name = name_table.resolve_ref(ic.name);
740 let refer_name_str = name_table.resolve_ref(refer_name);
741 let location = ic.source.as_ref().and_then(|s| source_maps.locate(s));
742 return Err(SchemaError::structural(
743 "src-identity-constraint",
744 format!(
745 "Keyref '{}': refer target '{}' not found among identity constraints",
746 ic_name, refer_name_str
747 ),
748 location,
749 ));
750 }
751 }
752 }
753 Some(target_ic) => {
754 check_keyref_target(
755 ic,
756 target_ic.kind,
757 target_ic.fields.len(),
758 refer_name,
759 name_table,
760 source_maps,
761 )?;
762 }
763 }
764 }
765 }
766 Ok(())
767}
768
769pub fn allocate_content_particle_elements(schema_set: &mut SchemaSet) -> SchemaResult<()> {
776 let mut jobs = Vec::new();
785 for (key, complex) in schema_set.arenas.complex_types.iter() {
786 let target_ns = complex.target_namespace;
787 if let ComplexContentResult::Complex(def) = &complex.content {
788 if let Some(particle) = &def.particle {
789 if let ParticleTerm::Group(group_def) = &particle.term {
790 let mut flat_idx = 0;
791 collect_content_particle_elements_recursive(
792 &group_def.particles,
793 key,
794 target_ns,
795 &mut flat_idx,
796 &mut jobs,
797 );
798 }
799 }
800 }
801 }
802 jobs.retain(|job| {
804 match schema_set
805 .arenas
806 .complex_types
807 .get(job.complex_type_key)
808 .and_then(|ct| ct.resolved_content_particle_elements.get(job.flat_idx))
809 {
810 Some(Some(_)) => false, _ => true,
812 }
813 });
814
815 let mut ic_names_by_doc: HashMap<DocumentId, HashSet<NameId>> = HashMap::new();
818 for ic in schema_set.arenas.identity_constraints.values() {
819 if let Some(source) = &ic.source {
820 ic_names_by_doc
821 .entry(source.doc_id)
822 .or_default()
823 .insert(ic.name);
824 }
825 }
826
827 for job in jobs {
829 if let Some(TypeRefResult::QName(qname)) = &job.elem.type_ref {
833 crate::schema::resolver::check_namespace_visible(
834 schema_set,
835 qname,
836 job.elem.source.as_ref(),
837 "Type",
838 )?;
839 }
840
841 let resolved_type = schema_set
842 .arenas
843 .complex_types
844 .get(job.complex_type_key)
845 .and_then(|ct| {
846 ct.resolved_content_particle_types
847 .get(job.flat_idx)
848 .copied()
849 .flatten()
850 })
851 .or_else(|| {
852 match &job.elem.type_ref {
854 Some(TypeRefResult::QName(qname)) => schema_set
855 .lookup_type(qname.namespace, qname.local_name)
856 .or_else(|| {
857 schema_set.get_built_in_type_by_qname(qname.namespace, qname.local_name)
858 }),
859 _ => None,
860 }
861 });
862
863 let resolved_type = resolved_type.or_else(|| match &job.elem.type_ref {
870 None => Some(TypeKey::Complex(schema_set.any_type_key())),
874 _ => None,
875 });
876
877 if resolved_type.is_none() {
880 if let Some(TypeRefResult::QName(qname)) = &job.elem.type_ref {
881 let display = crate::schema::resolver::format_resolved_qname(
882 &schema_set.name_table,
883 qname.namespace,
884 qname.local_name,
885 );
886 let location = schema_set.locate(job.elem.source.as_ref());
887 return Err(SchemaError::structural(
888 "src-resolve",
889 format!("Type reference '{}' on local element not found", display),
890 location,
891 ));
892 }
893 }
894
895 let effective_ns = schema_set.effective_local_element_namespace(
896 job.elem.target_namespace,
897 job.elem.form.as_deref(),
898 job.elem.source.as_ref(),
899 job.target_namespace,
900 );
901 validate_keyref_refers(
902 &job.elem.identity_constraints,
903 job.target_namespace,
904 &schema_set.name_table,
905 &schema_set.source_maps,
906 &schema_set.arenas.identity_constraints,
907 &schema_set.documents,
908 )?;
909 let mut identity_constraint_keys = Vec::with_capacity(job.elem.identity_constraints.len());
910 for ic in job.elem.identity_constraints {
911 if let Some(source) = &ic.source {
913 let doc_names = ic_names_by_doc.entry(source.doc_id).or_default();
914 if !doc_names.insert(ic.name) {
915 let location = schema_set.source_maps.locate(source);
916 let name_str = schema_set.name_table.resolve(ic.name);
917 return Err(SchemaError::structural(
918 "ic-unique",
919 format!(
920 "Duplicate identity constraint name '{}' in schema document",
921 name_str
922 ),
923 location,
924 ));
925 }
926 }
927 let ic_name = ic.name;
928 let ic_key = schema_set
929 .arenas
930 .alloc_identity_constraint(IdentityConstraintData {
931 kind: ic.kind,
932 name: ic.name,
933 ref_name: ic.ref_name,
934 refer: ic.refer,
935 selector: ic.selector,
936 fields: ic.fields,
937 id: ic.id,
938 annotation: ic.annotation,
939 source: ic.source,
940 });
941 let ns_table = schema_set.get_or_create_namespace(job.target_namespace);
943 ns_table.identity_constraints.insert(ic_name, ic_key);
944 identity_constraint_keys.push(ic_key);
945 }
946 for ic_ref in &job.elem.identity_constraint_refs {
948 let target_key = resolve_ic_ref(
949 ic_ref.kind,
950 &ic_ref.ref_name,
951 ic_ref.source.as_ref(),
952 job.target_namespace,
953 schema_set,
954 )?;
955 identity_constraint_keys.push(target_key);
956 }
957
958 let block = resolve_block(job.elem.block, job.elem.source.as_ref(), schema_set);
959 let final_derivation = resolve_final(
960 job.elem.final_derivation,
961 job.elem.source.as_ref(),
962 schema_set,
963 );
964 let elem_data = ElementDeclData {
965 name: job.elem.name,
966 target_namespace: effective_ns,
967 ref_name: None,
968 type_ref: job.elem.type_ref.clone(),
969 inline_type: job.elem.inline_type.clone(),
970 substitution_group: Vec::new(),
971 default_value: job.elem.default_value.clone(),
972 fixed_value: job.elem.fixed_value.clone(),
973 nillable: job.elem.nillable,
974 is_abstract: job.elem.is_abstract,
975 min_occurs: job.elem.min_occurs,
976 max_occurs: job.elem.max_occurs,
977 block,
978 final_derivation,
979 form: job.elem.form.clone(),
980 id: job.elem.id.clone(),
981 alternatives: job.elem.alternatives.clone(),
982 identity_constraints: identity_constraint_keys,
983 pending_ic_refs: vec![],
984 annotation: job.elem.annotation.clone(),
985 source: job.elem.source.clone(),
986 resolved_type,
987 resolved_ref: None,
988 resolved_substitution_groups: Vec::new(),
989 deferred_type_error: None,
990 };
991
992 let elem_key = schema_set.arenas.alloc_element(elem_data);
993
994 if let Some(ct) = schema_set
995 .arenas
996 .complex_types
997 .get_mut(job.complex_type_key)
998 {
999 while ct.resolved_content_particle_elements.len() <= job.flat_idx {
1000 ct.resolved_content_particle_elements.push(None);
1001 }
1002 ct.resolved_content_particle_elements[job.flat_idx] = Some(elem_key);
1003 }
1004 }
1005
1006 Ok(())
1007}
1008
1009#[cfg(feature = "xsd11")]
1035pub fn resolve_local_element_alternatives(
1036 schema_set: &mut SchemaSet,
1037) -> SchemaResult<Vec<ComplexTypeKey>> {
1038 use crate::ids::ComplexTypeKey;
1039
1040 let mut qname_pending: Vec<(ElementKey, usize, QNameRef, Option<SourceRef>)> = Vec::new();
1047 for (key, elem) in schema_set.arenas.elements.iter() {
1048 for (idx, alt) in elem.alternatives.iter().enumerate() {
1049 if alt.resolved_type.is_some() {
1050 continue;
1051 }
1052 if let Some(TypeRefResult::QName(qname)) = &alt.type_ref {
1053 qname_pending.push((key, idx, qname.clone(), alt.source.clone()));
1054 }
1055 }
1056 }
1057 for (elem_key, alt_idx, qname, src) in qname_pending {
1058 let resolver = crate::schema::resolver::ReferenceResolver::new(schema_set);
1059 let type_key = resolver.resolve_type_ref(&qname, src.as_ref())?;
1060 if let Some(elem) = schema_set.arenas.elements.get_mut(elem_key) {
1061 if let Some(alt) = elem.alternatives.get_mut(alt_idx) {
1062 alt.resolved_type = Some(type_key);
1063 }
1064 }
1065 }
1066
1067 let mut pending: Vec<(ElementKey, usize, TypeFrameResult, Option<NameId>)> = Vec::new();
1070 for (key, elem) in schema_set.arenas.elements.iter() {
1071 for (idx, alt) in elem.alternatives.iter().enumerate() {
1072 if alt.resolved_type.is_some() {
1073 continue;
1074 }
1075 let Some(inline_type) = &alt.inline_type else {
1076 continue;
1077 };
1078 pending.push((key, idx, (**inline_type).clone(), elem.target_namespace));
1079 }
1080 }
1081
1082 let mut new_complex_keys: Vec<ComplexTypeKey> = Vec::new();
1083 for (elem_key, alt_idx, type_frame, target_ns) in pending {
1084 let type_key = assemble_inline_type(schema_set, &type_frame, target_ns)?;
1085 if let TypeKey::Complex(ct_key) = type_key {
1086 new_complex_keys.push(ct_key);
1087 }
1088 if let Some(elem) = schema_set.arenas.elements.get_mut(elem_key) {
1089 if let Some(alt) = elem.alternatives.get_mut(alt_idx) {
1090 alt.resolved_type = Some(type_key);
1091 }
1092 }
1093 }
1094
1095 Ok(new_complex_keys)
1096}
1097
1098struct ModelGroupElementJob {
1100 group_key: ModelGroupKey,
1101 particle_idx: usize,
1102 elem: ElementFrameResult,
1103 target_namespace: Option<NameId>,
1104}
1105
1106pub fn allocate_model_group_particle_elements(schema_set: &mut SchemaSet) -> SchemaResult<()> {
1113 let mut jobs = Vec::new();
1115 for (key, group) in schema_set.arenas.model_groups.iter() {
1116 let target_ns = group.target_namespace;
1117 let mut flat_idx = 0;
1118 collect_model_group_elements_recursive(
1119 &group.particles,
1120 key,
1121 target_ns,
1122 &mut flat_idx,
1123 &mut jobs,
1124 );
1125 }
1126
1127 let mut ic_names_by_doc: HashMap<DocumentId, HashSet<NameId>> = HashMap::new();
1130 for ic in schema_set.arenas.identity_constraints.values() {
1131 if let Some(source) = &ic.source {
1132 ic_names_by_doc
1133 .entry(source.doc_id)
1134 .or_default()
1135 .insert(ic.name);
1136 }
1137 }
1138
1139 for job in jobs {
1141 if let Some(TypeRefResult::QName(qname)) = &job.elem.type_ref {
1143 crate::schema::resolver::check_namespace_visible(
1144 schema_set,
1145 qname,
1146 job.elem.source.as_ref(),
1147 "Type",
1148 )?;
1149 }
1150
1151 let resolved_type = schema_set
1152 .arenas
1153 .model_groups
1154 .get(job.group_key)
1155 .and_then(|g| {
1156 g.resolved_particle_types
1157 .get(job.particle_idx)
1158 .copied()
1159 .flatten()
1160 })
1161 .or_else(|| {
1162 match &job.elem.type_ref {
1164 Some(TypeRefResult::QName(qname)) => schema_set
1165 .lookup_type(qname.namespace, qname.local_name)
1166 .or_else(|| {
1167 schema_set.get_built_in_type_by_qname(qname.namespace, qname.local_name)
1168 }),
1169 _ => None,
1170 }
1171 });
1172
1173 let effective_ns = schema_set.effective_local_element_namespace(
1174 job.elem.target_namespace,
1175 job.elem.form.as_deref(),
1176 job.elem.source.as_ref(),
1177 job.target_namespace,
1178 );
1179 validate_keyref_refers(
1180 &job.elem.identity_constraints,
1181 job.target_namespace,
1182 &schema_set.name_table,
1183 &schema_set.source_maps,
1184 &schema_set.arenas.identity_constraints,
1185 &schema_set.documents,
1186 )?;
1187 let mut identity_constraint_keys = Vec::with_capacity(job.elem.identity_constraints.len());
1188 for ic in job.elem.identity_constraints {
1189 if let Some(source) = &ic.source {
1191 let doc_names = ic_names_by_doc.entry(source.doc_id).or_default();
1192 if !doc_names.insert(ic.name) {
1193 let location = schema_set.source_maps.locate(source);
1194 let name_str = schema_set.name_table.resolve(ic.name);
1195 return Err(SchemaError::structural(
1196 "ic-unique",
1197 format!(
1198 "Duplicate identity constraint name '{}' in schema document",
1199 name_str
1200 ),
1201 location,
1202 ));
1203 }
1204 }
1205 let ic_name = ic.name;
1206 let ic_key = schema_set
1207 .arenas
1208 .alloc_identity_constraint(IdentityConstraintData {
1209 kind: ic.kind,
1210 name: ic.name,
1211 ref_name: ic.ref_name,
1212 refer: ic.refer,
1213 selector: ic.selector,
1214 fields: ic.fields,
1215 id: ic.id,
1216 annotation: ic.annotation,
1217 source: ic.source,
1218 });
1219 let ns_table = schema_set.get_or_create_namespace(job.target_namespace);
1221 ns_table.identity_constraints.insert(ic_name, ic_key);
1222 identity_constraint_keys.push(ic_key);
1223 }
1224 for ic_ref in &job.elem.identity_constraint_refs {
1226 let target_key = resolve_ic_ref(
1227 ic_ref.kind,
1228 &ic_ref.ref_name,
1229 ic_ref.source.as_ref(),
1230 job.target_namespace,
1231 schema_set,
1232 )?;
1233 identity_constraint_keys.push(target_key);
1234 }
1235
1236 let block = resolve_block(job.elem.block, job.elem.source.as_ref(), schema_set);
1237 let final_derivation = resolve_final(
1238 job.elem.final_derivation,
1239 job.elem.source.as_ref(),
1240 schema_set,
1241 );
1242 let elem_data = ElementDeclData {
1243 name: job.elem.name,
1244 target_namespace: effective_ns,
1245 ref_name: None,
1246 type_ref: job.elem.type_ref.clone(),
1247 inline_type: job.elem.inline_type.clone(),
1248 substitution_group: Vec::new(),
1249 default_value: job.elem.default_value.clone(),
1250 fixed_value: job.elem.fixed_value.clone(),
1251 nillable: job.elem.nillable,
1252 is_abstract: job.elem.is_abstract,
1253 min_occurs: job.elem.min_occurs,
1254 max_occurs: job.elem.max_occurs,
1255 block,
1256 final_derivation,
1257 form: job.elem.form.clone(),
1258 id: job.elem.id.clone(),
1259 alternatives: job.elem.alternatives.clone(),
1260 identity_constraints: identity_constraint_keys,
1261 pending_ic_refs: vec![],
1262 annotation: job.elem.annotation.clone(),
1263 source: job.elem.source.clone(),
1264 resolved_type,
1265 resolved_ref: None,
1266 resolved_substitution_groups: Vec::new(),
1267 deferred_type_error: None,
1268 };
1269
1270 let elem_key = schema_set.arenas.alloc_element(elem_data);
1271
1272 if let Some(group) = schema_set.arenas.model_groups.get_mut(job.group_key) {
1273 while group.resolved_particle_elements.len() <= job.particle_idx {
1274 group.resolved_particle_elements.push(None);
1275 }
1276 group.resolved_particle_elements[job.particle_idx] = Some(elem_key);
1277 }
1278 }
1279
1280 Ok(())
1281}
1282
1283fn collect_model_group_elements_recursive(
1285 particles: &[ParticleResult],
1286 group_key: ModelGroupKey,
1287 target_ns: Option<NameId>,
1288 flat_idx: &mut usize,
1289 jobs: &mut Vec<ModelGroupElementJob>,
1290) {
1291 for particle in particles {
1292 match &particle.term {
1293 ParticleTerm::Element(elem) if elem.ref_name.is_none() => {
1294 jobs.push(ModelGroupElementJob {
1295 group_key,
1296 particle_idx: *flat_idx,
1297 elem: elem.clone(),
1298 target_namespace: target_ns,
1299 });
1300 *flat_idx += 1;
1301 }
1302 ParticleTerm::Element(_) => {
1303 *flat_idx += 1;
1305 }
1306 ParticleTerm::Group(group_def) if group_def.ref_name.is_none() => {
1307 collect_model_group_elements_recursive(
1308 &group_def.particles,
1309 group_key,
1310 target_ns,
1311 flat_idx,
1312 jobs,
1313 );
1314 }
1315 _ => {} }
1317 }
1318}
1319
1320fn assemble_inline_type(
1325 schema_set: &mut SchemaSet,
1326 type_frame: &TypeFrameResult,
1327 target_namespace: Option<NameId>,
1328) -> SchemaResult<TypeKey> {
1329 match type_frame {
1330 TypeFrameResult::Simple(simple) => {
1331 let final_derivation =
1332 resolve_final(simple.final_derivation, simple.source.as_ref(), schema_set);
1333 let data = SimpleTypeDefData {
1334 name: simple.name, target_namespace,
1336 variety: simple.variety,
1337 base_type: simple.base_type.clone(),
1338 item_type: simple.item_type.clone(),
1339 member_types: simple.member_types.clone(),
1340 facets: simple.facets.clone(),
1341 final_derivation,
1342 id: simple.id.clone(),
1343 derivation_id: simple.derivation_id.clone(),
1344 annotation: simple.annotation.clone(),
1345 source: simple.source.clone(),
1346 resolved_base_type: None,
1348 resolved_item_type: None,
1349 resolved_member_types: Vec::new(),
1350 redefine_original: None,
1351 deferred_item_type_error: None,
1352 };
1353 let key = schema_set.arenas.alloc_simple_type(data);
1354 Ok(TypeKey::Simple(key))
1355 }
1356 TypeFrameResult::Complex(complex) => {
1357 let open_content = match &complex.content {
1358 ComplexContentResult::Complex(def) => def.open_content.clone(),
1359 _ => None,
1360 };
1361 #[cfg(feature = "xsd11")]
1362 let assertions = match &complex.content {
1363 ComplexContentResult::Simple(sc) => sc.assertions.clone(),
1364 ComplexContentResult::Complex(cc) => cc.assertions.clone(),
1365 ComplexContentResult::Empty => Vec::new(),
1366 };
1367 let block = resolve_block(complex.block, complex.source.as_ref(), schema_set);
1368 let final_derivation = resolve_final(
1369 complex.final_derivation,
1370 complex.source.as_ref(),
1371 schema_set,
1372 );
1373 let data = ComplexTypeDefData {
1374 name: complex.name, target_namespace,
1376 base_type: complex.base_type.clone(),
1377 derivation_method: complex.derivation_method,
1378 content: complex.content.clone(),
1379 open_content,
1380 attributes: complex.attributes.clone(),
1381 attribute_groups: complex.attribute_groups.clone(),
1382 attribute_wildcard: complex.attribute_wildcard.clone(),
1383 mixed: complex.mixed,
1384 is_abstract: complex.is_abstract,
1385 final_derivation,
1386 block,
1387 default_attributes_apply: complex.default_attributes_apply,
1388 id: complex.id.clone(),
1389 #[cfg(feature = "xsd11")]
1390 assertions,
1391 #[cfg(feature = "xsd11")]
1392 xpath_default_namespace: complex.xpath_default_namespace.clone(),
1393 annotation: complex.annotation.clone(),
1394 source: complex.source.clone(),
1395 resolved_base_type: None,
1397 resolved_attribute_groups: Vec::new(),
1398 resolved_attributes: Vec::new(),
1399 resolved_content_particle_types: Vec::new(),
1400 resolved_content_particle_elements: Vec::new(),
1401 resolved_simple_content_type: None,
1402 redefine_original: None,
1403 };
1404 let key = schema_set.arenas.alloc_complex_type(data);
1405 Ok(TypeKey::Complex(key))
1406 }
1407 }
1408}
1409
1410fn update_owner(
1412 schema_set: &mut SchemaSet,
1413 job: &InlineTypeJob,
1414 type_key: TypeKey,
1415 stats: &mut InlineAssemblyStats,
1416) -> SchemaResult<()> {
1417 match job.owner {
1418 InlineOwner::Element(key) => {
1419 if let Some(elem) = schema_set.arenas.elements.get_mut(key) {
1420 match job.role {
1421 #[cfg(feature = "xsd11")]
1422 InlineRole::AlternativeType(idx) => {
1423 if let Some(alt) = elem.alternatives.get_mut(idx) {
1424 alt.resolved_type = Some(type_key);
1425 }
1426 }
1427 _ => {
1428 elem.resolved_type = Some(type_key);
1429 stats.element_inline_types += 1;
1430 }
1431 }
1432 stats.total_inline_types += 1;
1433 }
1434 }
1435 InlineOwner::Attribute(key) => {
1436 if let Some(attr) = schema_set.arenas.attributes.get_mut(key) {
1437 attr.resolved_type = Some(type_key);
1438 stats.attribute_inline_types += 1;
1439 stats.total_inline_types += 1;
1440 }
1441 }
1442 InlineOwner::SimpleType(key) => {
1443 if let Some(simple) = schema_set.arenas.simple_types.get_mut(key) {
1444 match job.role {
1445 InlineRole::SimpleTypeBase => {
1446 simple.resolved_base_type = Some(type_key);
1447 }
1448 InlineRole::ListItemType => {
1449 simple.resolved_item_type = Some(type_key);
1450 }
1451 InlineRole::UnionMemberType(idx) => {
1452 while simple.resolved_member_types.len() <= idx {
1455 simple.resolved_member_types.push(type_key);
1458 }
1459 simple.resolved_member_types[idx] = type_key;
1460 }
1461 _ => {}
1462 }
1463 stats.simple_type_inline_derivations += 1;
1464 stats.total_inline_types += 1;
1465 }
1466 }
1467 InlineOwner::ComplexType(key) => {
1468 if let Some(complex) = schema_set.arenas.complex_types.get_mut(key) {
1469 match job.role {
1470 InlineRole::ComplexTypeBase => {
1471 complex.resolved_base_type = Some(type_key);
1472 stats.complex_type_inline_derivations += 1;
1473 }
1474 InlineRole::ComplexTypeAttribute(idx) => {
1475 while complex.resolved_attributes.len() <= idx {
1477 complex.resolved_attributes.push(ResolvedAttributeUse {
1478 resolved_type: None,
1479 resolved_ref: None,
1480 });
1481 }
1482 complex.resolved_attributes[idx].resolved_type = Some(type_key);
1483 stats.complex_type_attribute_inline_types += 1;
1484 }
1485 InlineRole::ContentParticleType(idx) => {
1486 while complex.resolved_content_particle_types.len() <= idx {
1487 complex.resolved_content_particle_types.push(None);
1488 }
1489 complex.resolved_content_particle_types[idx] = Some(type_key);
1490 stats.complex_type_inline_derivations += 1;
1491 }
1492 InlineRole::SimpleContentInlineType => {
1493 complex.resolved_simple_content_type = Some(type_key);
1494 stats.complex_type_inline_derivations += 1;
1495 }
1496 _ => {}
1497 }
1498 stats.total_inline_types += 1;
1499 }
1500 }
1501 InlineOwner::ModelGroup(key) => {
1502 if let Some(group) = schema_set.arenas.model_groups.get_mut(key) {
1503 if let InlineRole::ModelGroupParticle(flat_idx) = job.role {
1504 while group.resolved_particle_types.len() <= flat_idx {
1506 group.resolved_particle_types.push(None);
1507 }
1508 group.resolved_particle_types[flat_idx] = Some(type_key);
1509 stats.model_group_inline_types += 1;
1510 stats.total_inline_types += 1;
1511 }
1512 }
1513 }
1514 InlineOwner::AttributeGroup(key) => {
1515 if let Some(group) = schema_set.arenas.attribute_groups.get_mut(key) {
1516 if let InlineRole::AttributeGroupAttribute(idx) = job.role {
1517 while group.resolved_attributes.len() <= idx {
1519 group.resolved_attributes.push(ResolvedAttributeUse {
1520 resolved_type: None,
1521 resolved_ref: None,
1522 });
1523 }
1524 group.resolved_attributes[idx].resolved_type = Some(type_key);
1525 stats.attribute_group_inline_types += 1;
1526 stats.total_inline_types += 1;
1527 }
1528 }
1529 }
1530 }
1531 Ok(())
1532}
1533
1534fn collect_nested_inline_types(
1536 schema_set: &SchemaSet,
1537 type_key: TypeKey,
1538 target_namespace: Option<NameId>,
1539 jobs: &mut Vec<InlineTypeJob>,
1540) {
1541 match type_key {
1542 TypeKey::Simple(key) => {
1543 if let Some(simple) = schema_set.arenas.simple_types.get(key) {
1544 if let Some(TypeRefResult::Inline(inline_type)) = &simple.base_type {
1546 jobs.push(InlineTypeJob {
1547 owner: InlineOwner::SimpleType(key),
1548 role: InlineRole::SimpleTypeBase,
1549 type_frame: (**inline_type).clone(),
1550 target_namespace,
1551 });
1552 }
1553 if let Some(TypeRefResult::Inline(inline_type)) = &simple.item_type {
1554 jobs.push(InlineTypeJob {
1555 owner: InlineOwner::SimpleType(key),
1556 role: InlineRole::ListItemType,
1557 type_frame: (**inline_type).clone(),
1558 target_namespace,
1559 });
1560 }
1561 for (idx, member) in simple.member_types.iter().enumerate() {
1562 if let TypeRefResult::Inline(inline_type) = member {
1563 jobs.push(InlineTypeJob {
1564 owner: InlineOwner::SimpleType(key),
1565 role: InlineRole::UnionMemberType(idx),
1566 type_frame: (**inline_type).clone(),
1567 target_namespace,
1568 });
1569 }
1570 }
1571 }
1572 }
1573 TypeKey::Complex(key) => {
1574 if let Some(complex) = schema_set.arenas.complex_types.get(key) {
1575 if let Some(TypeRefResult::Inline(inline_type)) = &complex.base_type {
1577 jobs.push(InlineTypeJob {
1578 owner: InlineOwner::ComplexType(key),
1579 role: InlineRole::ComplexTypeBase,
1580 type_frame: (**inline_type).clone(),
1581 target_namespace,
1582 });
1583 }
1584
1585 for (idx, attr_use) in complex.attributes.iter().enumerate() {
1587 if let Some(inline_type) = &attr_use.attribute.inline_type {
1588 jobs.push(InlineTypeJob {
1589 owner: InlineOwner::ComplexType(key),
1590 role: InlineRole::ComplexTypeAttribute(idx),
1591 type_frame: TypeFrameResult::Simple(Box::new((**inline_type).clone())),
1592 target_namespace,
1593 });
1594 }
1595 }
1596
1597 collect_content_inline_types(&complex.content, key, target_namespace, jobs);
1599 }
1600 }
1601 }
1602}
1603
1604#[cfg(test)]
1605mod tests {
1606 use super::*;
1607 use crate::arenas::ElementDeclData;
1608 use crate::parser::frames::{SimpleTypeResult, SimpleTypeVariety};
1609 use crate::schema::model::DerivationSet;
1610 use crate::types::facets::FacetSet;
1611
1612 fn create_simple_type_frame(variety: SimpleTypeVariety) -> TypeFrameResult {
1613 TypeFrameResult::Simple(Box::new(SimpleTypeResult {
1614 name: None,
1615 variety,
1616 base_type: None,
1617 item_type: None,
1618 member_types: Vec::new(),
1619 facets: FacetSet::new(),
1620 final_derivation: None,
1621 id: None,
1622 derivation_id: None,
1623 annotation: None,
1624 source: None,
1625 }))
1626 }
1627
1628 #[test]
1629 fn test_assemble_inline_types_empty_schema() {
1630 let mut schema_set = SchemaSet::new();
1631 let result = assemble_inline_types(&mut schema_set);
1632 assert!(result.is_ok());
1633 let stats = result.unwrap();
1634 assert_eq!(stats.total_inline_types, 0);
1635 }
1636
1637 #[test]
1638 fn test_element_with_inline_simple_type() {
1639 let mut schema_set = SchemaSet::new();
1640
1641 let elem_name = schema_set.name_table.add("testElement");
1642 let inline_type = Box::new(create_simple_type_frame(SimpleTypeVariety::Atomic));
1643
1644 let elem_data = ElementDeclData {
1645 name: Some(elem_name),
1646 target_namespace: None,
1647 ref_name: None,
1648 type_ref: None,
1649 inline_type: Some(inline_type),
1650 substitution_group: Vec::new(),
1651 default_value: None,
1652 fixed_value: None,
1653 nillable: false,
1654 is_abstract: false,
1655 min_occurs: 1,
1656 max_occurs: Some(1),
1657 block: DerivationSet::empty(),
1658 final_derivation: DerivationSet::empty(),
1659 form: None,
1660 id: None,
1661 alternatives: Vec::new(),
1662 identity_constraints: Vec::new(),
1663 pending_ic_refs: vec![],
1664 annotation: None,
1665 source: None,
1666 resolved_type: None,
1667 resolved_ref: None,
1668 resolved_substitution_groups: Vec::new(),
1669 deferred_type_error: None,
1670 };
1671
1672 let elem_key = schema_set.arenas.alloc_element(elem_data);
1673
1674 let result = assemble_inline_types(&mut schema_set);
1676 assert!(result.is_ok());
1677 let stats = result.unwrap();
1678 assert_eq!(stats.element_inline_types, 1);
1679 assert_eq!(stats.total_inline_types, 1);
1680
1681 let elem = schema_set.arenas.elements.get(elem_key).unwrap();
1683 assert!(elem.resolved_type.is_some());
1684 assert!(matches!(elem.resolved_type, Some(TypeKey::Simple(_))));
1685
1686 assert!(elem.inline_type.is_some());
1688 }
1689
1690 #[test]
1691 fn test_simple_type_with_inline_base() {
1692 let mut schema_set = SchemaSet::new();
1693
1694 let type_name = schema_set.name_table.add("testType");
1695 let inline_base = Box::new(create_simple_type_frame(SimpleTypeVariety::Atomic));
1696
1697 let type_data = SimpleTypeDefData {
1698 name: Some(type_name),
1699 target_namespace: None,
1700 variety: SimpleTypeVariety::Atomic,
1701 base_type: Some(TypeRefResult::Inline(inline_base)),
1702 item_type: None,
1703 member_types: Vec::new(),
1704 facets: FacetSet::new(),
1705 final_derivation: DerivationSet::empty(),
1706 id: None,
1707 derivation_id: None,
1708 annotation: None,
1709 source: None,
1710 resolved_base_type: None,
1711 resolved_item_type: None,
1712 resolved_member_types: Vec::new(),
1713 redefine_original: None,
1714 deferred_item_type_error: None,
1715 };
1716
1717 let type_key = schema_set.arenas.alloc_simple_type(type_data);
1718
1719 let result = assemble_inline_types(&mut schema_set);
1721 assert!(result.is_ok());
1722 let stats = result.unwrap();
1723 assert_eq!(stats.simple_type_inline_derivations, 1);
1724
1725 let simple = schema_set.arenas.simple_types.get(type_key).unwrap();
1727 assert!(simple.resolved_base_type.is_some());
1728
1729 assert!(matches!(simple.base_type, Some(TypeRefResult::Inline(_))));
1731 }
1732
1733 #[test]
1734 fn test_list_type_with_inline_item() {
1735 let mut schema_set = SchemaSet::new();
1736
1737 let type_name = schema_set.name_table.add("listType");
1738 let inline_item = Box::new(create_simple_type_frame(SimpleTypeVariety::Atomic));
1739
1740 let type_data = SimpleTypeDefData {
1741 name: Some(type_name),
1742 target_namespace: None,
1743 variety: SimpleTypeVariety::List,
1744 base_type: None,
1745 item_type: Some(TypeRefResult::Inline(inline_item)),
1746 member_types: Vec::new(),
1747 facets: FacetSet::new(),
1748 final_derivation: DerivationSet::empty(),
1749 id: None,
1750 derivation_id: None,
1751 annotation: None,
1752 source: None,
1753 resolved_base_type: None,
1754 resolved_item_type: None,
1755 resolved_member_types: Vec::new(),
1756 redefine_original: None,
1757 deferred_item_type_error: None,
1758 };
1759
1760 let type_key = schema_set.arenas.alloc_simple_type(type_data);
1761
1762 let result = assemble_inline_types(&mut schema_set);
1764 assert!(result.is_ok());
1765
1766 let simple = schema_set.arenas.simple_types.get(type_key).unwrap();
1768 assert!(simple.resolved_item_type.is_some());
1769 }
1770
1771 #[test]
1772 fn test_union_type_with_inline_members() {
1773 let mut schema_set = SchemaSet::new();
1774
1775 let type_name = schema_set.name_table.add("unionType");
1776 let inline_member1 = Box::new(create_simple_type_frame(SimpleTypeVariety::Atomic));
1777 let inline_member2 = Box::new(create_simple_type_frame(SimpleTypeVariety::Atomic));
1778
1779 let type_data = SimpleTypeDefData {
1780 name: Some(type_name),
1781 target_namespace: None,
1782 variety: SimpleTypeVariety::Union,
1783 base_type: None,
1784 item_type: None,
1785 member_types: vec![
1786 TypeRefResult::Inline(inline_member1),
1787 TypeRefResult::Inline(inline_member2),
1788 ],
1789 facets: FacetSet::new(),
1790 final_derivation: DerivationSet::empty(),
1791 id: None,
1792 derivation_id: None,
1793 annotation: None,
1794 source: None,
1795 resolved_base_type: None,
1796 resolved_item_type: None,
1797 resolved_member_types: Vec::new(),
1798 redefine_original: None,
1799 deferred_item_type_error: None,
1800 };
1801
1802 let type_key = schema_set.arenas.alloc_simple_type(type_data);
1803
1804 let result = assemble_inline_types(&mut schema_set);
1806 assert!(result.is_ok());
1807 let stats = result.unwrap();
1808 assert_eq!(stats.simple_type_inline_derivations, 2);
1809
1810 let simple = schema_set.arenas.simple_types.get(type_key).unwrap();
1812 assert_eq!(simple.resolved_member_types.len(), 2);
1813 }
1814
1815 #[test]
1816 fn test_inline_type_in_model_group_resolved() {
1817 use crate::arenas::ModelGroupData;
1818 use crate::parser::frames::{Compositor, ElementFrameResult};
1819
1820 let mut schema_set = SchemaSet::new();
1821
1822 let elem_name = schema_set.name_table.add("detail");
1823 let inline_type = Box::new(create_simple_type_frame(SimpleTypeVariety::Atomic));
1824
1825 let group_data = ModelGroupData {
1827 name: Some(schema_set.name_table.add("myGroup")),
1828 target_namespace: None,
1829 ref_name: None,
1830 compositor: Some(Compositor::Sequence),
1831 particles: vec![ParticleResult {
1832 term: ParticleTerm::Element(ElementFrameResult {
1833 name: Some(elem_name),
1834 ref_name: None,
1835 target_namespace: None,
1836 type_ref: None,
1837 inline_type: Some(inline_type),
1838 substitution_group: vec![],
1839 default_value: None,
1840 fixed_value: None,
1841 nillable: false,
1842 is_abstract: false,
1843 min_occurs: 1,
1844 max_occurs: Some(1),
1845 block: Default::default(),
1846 final_derivation: Default::default(),
1847 form: None,
1848 id: None,
1849 alternatives: vec![],
1850 identity_constraints: vec![],
1851 identity_constraint_refs: vec![],
1852 annotation: None,
1853 source: None,
1854 }),
1855 min_occurs: 1,
1856 max_occurs: Some(1),
1857 source: None,
1858 }],
1859 min_occurs: 1,
1860 max_occurs: Some(1),
1861 id: None,
1862 annotation: None,
1863 source: None,
1864 resolved_ref: None,
1865 resolved_particles: Vec::new(),
1866 resolved_particle_types: Vec::new(),
1867 resolved_particle_elements: Vec::new(),
1868 redefine_original: None,
1869 redefine_requires_restriction_check: false,
1870 };
1871
1872 let _group_key = schema_set.arenas.alloc_model_group(group_data);
1873
1874 let result = assemble_inline_types(&mut schema_set);
1875 assert!(result.is_ok());
1876 let stats = result.unwrap();
1877 assert_eq!(stats.model_group_inline_types, 1);
1878 assert_eq!(stats.total_inline_types, 1);
1879
1880 let group = schema_set.arenas.model_groups.get(_group_key).unwrap();
1882 assert_eq!(group.resolved_particle_types.len(), 1);
1883 assert!(
1884 group.resolved_particle_types[0].is_some(),
1885 "Expected resolved type at flat index 0"
1886 );
1887 }
1888
1889 #[test]
1890 fn test_inline_type_in_content_particle_resolved() {
1891 use crate::parser::frames::{
1892 ComplexContentDefResult, Compositor, ElementFrameResult, ModelGroupDefResult,
1893 };
1894
1895 let mut schema_set = SchemaSet::new();
1896
1897 let elem_name = schema_set.name_table.add("child");
1898 let inline_type = Box::new(create_simple_type_frame(SimpleTypeVariety::Atomic));
1899
1900 let content_particle = ParticleResult {
1902 term: ParticleTerm::Group(ModelGroupDefResult {
1903 name: None,
1904 ref_name: None,
1905 compositor: Some(Compositor::Sequence),
1906 particles: vec![ParticleResult {
1907 term: ParticleTerm::Element(ElementFrameResult {
1908 name: Some(elem_name),
1909 ref_name: None,
1910 target_namespace: None,
1911 type_ref: None,
1912 inline_type: Some(inline_type),
1913 substitution_group: vec![],
1914 default_value: None,
1915 fixed_value: None,
1916 nillable: false,
1917 is_abstract: false,
1918 min_occurs: 1,
1919 max_occurs: Some(1),
1920 block: Default::default(),
1921 final_derivation: Default::default(),
1922 form: None,
1923 id: None,
1924 alternatives: vec![],
1925 identity_constraints: vec![],
1926 identity_constraint_refs: vec![],
1927 annotation: None,
1928 source: None,
1929 }),
1930 min_occurs: 1,
1931 max_occurs: Some(1),
1932 source: None,
1933 }],
1934 min_occurs: 1,
1935 max_occurs: Some(1),
1936 id: None,
1937 annotation: None,
1938 source: None,
1939 }),
1940 min_occurs: 1,
1941 max_occurs: Some(1),
1942 source: None,
1943 };
1944
1945 let complex_data = ComplexTypeDefData {
1946 name: Some(schema_set.name_table.add("MyComplexType")),
1947 target_namespace: None,
1948 base_type: None,
1949 derivation_method: None,
1950 content: ComplexContentResult::Complex(ComplexContentDefResult {
1951 particle: Some(content_particle),
1952 derivation: crate::parser::frames::DerivationMethod::Restriction,
1953 mixed: false,
1954 mixed_explicit: false,
1955 base_type: None,
1956 open_content: None,
1957 attributes: Vec::new(),
1958 attribute_groups: Vec::new(),
1959 attribute_wildcard: None,
1960 assertions: Vec::new(),
1961 id: None,
1962 derivation_id: None,
1963 source: None,
1964 }),
1965 open_content: None,
1966 attributes: Vec::new(),
1967 attribute_groups: Vec::new(),
1968 attribute_wildcard: None,
1969 mixed: false,
1970 is_abstract: false,
1971 final_derivation: DerivationSet::empty(),
1972 block: DerivationSet::empty(),
1973 default_attributes_apply: true,
1974 id: None,
1975 #[cfg(feature = "xsd11")]
1976 assertions: Vec::new(),
1977 #[cfg(feature = "xsd11")]
1978 xpath_default_namespace: None,
1979 annotation: None,
1980 source: None,
1981 resolved_base_type: None,
1982 resolved_attribute_groups: Vec::new(),
1983 resolved_attributes: Vec::new(),
1984 resolved_content_particle_types: Vec::new(),
1985 resolved_content_particle_elements: Vec::new(),
1986 resolved_simple_content_type: None,
1987 redefine_original: None,
1988 };
1989
1990 let ct_key = schema_set.arenas.alloc_complex_type(complex_data);
1991
1992 let result = assemble_inline_types(&mut schema_set);
1993 assert!(result.is_ok());
1994 let stats = result.unwrap();
1995 assert!(stats.total_inline_types >= 1);
1996
1997 let ct = schema_set.arenas.complex_types.get(ct_key).unwrap();
1999 assert_eq!(ct.resolved_content_particle_types.len(), 1);
2000 assert!(ct.resolved_content_particle_types[0].is_some());
2001 }
2002
2003 #[test]
2004 fn test_nested_inline_type_in_model_group() {
2005 use crate::arenas::ModelGroupData;
2006 use crate::parser::frames::{Compositor, ElementFrameResult, ModelGroupDefResult};
2007
2008 let mut schema_set = SchemaSet::new();
2009
2010 let elem_name = schema_set.name_table.add("nested_elem");
2011 let inline_type = Box::new(create_simple_type_frame(SimpleTypeVariety::Atomic));
2012
2013 let group_data = ModelGroupData {
2024 name: Some(schema_set.name_table.add("G")),
2025 target_namespace: None,
2026 ref_name: None,
2027 compositor: Some(Compositor::Sequence),
2028 particles: vec![ParticleResult {
2029 term: ParticleTerm::Group(ModelGroupDefResult {
2030 name: None,
2031 ref_name: None,
2032 compositor: Some(Compositor::Choice),
2033 particles: vec![ParticleResult {
2034 term: ParticleTerm::Element(ElementFrameResult {
2035 name: Some(elem_name),
2036 ref_name: None,
2037 target_namespace: None,
2038 type_ref: None,
2039 inline_type: Some(inline_type),
2040 substitution_group: vec![],
2041 default_value: None,
2042 fixed_value: None,
2043 nillable: false,
2044 is_abstract: false,
2045 min_occurs: 1,
2046 max_occurs: Some(1),
2047 block: Default::default(),
2048 final_derivation: Default::default(),
2049 form: None,
2050 id: None,
2051 alternatives: vec![],
2052 identity_constraints: vec![],
2053 identity_constraint_refs: vec![],
2054 annotation: None,
2055 source: None,
2056 }),
2057 min_occurs: 1,
2058 max_occurs: Some(1),
2059 source: None,
2060 }],
2061 min_occurs: 1,
2062 max_occurs: Some(1),
2063 id: None,
2064 annotation: None,
2065 source: None,
2066 }),
2067 min_occurs: 1,
2068 max_occurs: Some(1),
2069 source: None,
2070 }],
2071 min_occurs: 1,
2072 max_occurs: Some(1),
2073 id: None,
2074 annotation: None,
2075 source: None,
2076 resolved_ref: None,
2077 resolved_particles: Vec::new(),
2078 resolved_particle_types: Vec::new(),
2079 resolved_particle_elements: Vec::new(),
2080 redefine_original: None,
2081 redefine_requires_restriction_check: false,
2082 };
2083
2084 let group_key = schema_set.arenas.alloc_model_group(group_data);
2085
2086 let result = assemble_inline_types(&mut schema_set);
2088 assert!(result.is_ok());
2089 let stats = result.unwrap();
2090 assert_eq!(stats.model_group_inline_types, 1);
2091 assert_eq!(stats.total_inline_types, 1);
2092
2093 let group = schema_set.arenas.model_groups.get(group_key).unwrap();
2095 assert_eq!(group.resolved_particle_types.len(), 1);
2096 assert!(
2097 group.resolved_particle_types[0].is_some(),
2098 "Expected resolved type for nested element at flat index 0"
2099 );
2100 assert!(matches!(
2101 group.resolved_particle_types[0],
2102 Some(TypeKey::Simple(_))
2103 ));
2104 }
2105}