xsd_parser/optimizer/
merge_choice_cardinality.rs1use crate::{
2 schema::MaxOccurs,
3 types::{Ident, TypeVariant},
4};
5
6use super::{Error, Optimizer};
7
8impl Optimizer {
9 #[doc = include_str!("../../tests/optimizer/complex_choice.xsd")]
22 #[doc = include_str!("../../tests/optimizer/expected0/merge_choice_cardinalities.rs")]
27 #[doc = include_str!("../../tests/optimizer/expected1/merge_choice_cardinalities.rs")]
32 pub fn merge_choice_cardinality(mut self, ident: Ident) -> Result<Self, Error> {
34 tracing::debug!("merge_choice_cardinality(ident={ident:?})");
35
36 let Some(ty) = self.types.get_variant(&ident) else {
37 return Err(Error::UnknownType(ident));
38 };
39
40 let TypeVariant::ComplexType(ci) = ty else {
41 return Err(Error::ExpectedComplexType(ident));
42 };
43
44 let Some(content_ident) = ci.content.clone() else {
45 return Err(Error::MissingContentType(ident));
46 };
47
48 let Some(TypeVariant::Choice(ci)) = self.types.get_variant_mut(&content_ident) else {
49 return Err(Error::ExpectedComplexChoice(ident));
50 };
51
52 let mut min = 1;
53 let mut max = MaxOccurs::Bounded(1);
54
55 for element in &mut *ci.elements {
56 min = min.min(element.min_occurs);
57 max = max.max(element.max_occurs);
58
59 element.min_occurs = 1;
60 element.max_occurs = MaxOccurs::Bounded(1);
61 }
62
63 let Some(TypeVariant::ComplexType(ci)) = self.types.get_variant_mut(&ident) else {
64 unreachable!();
65 };
66
67 ci.min_occurs = min.min(ci.min_occurs);
68 ci.max_occurs = max.max(ci.max_occurs);
69
70 Ok(self)
71 }
72
73 pub fn merge_choice_cardinalities(mut self) -> Self {
78 tracing::debug!("merge_choice_cardinalities");
79
80 let idents = self
81 .types
82 .iter()
83 .filter_map(|(ident, type_)| {
84 if matches!(&type_.variant, TypeVariant::ComplexType(ci) if ci.has_complex_choice_content(&self.types)) {
85 Some(ident)
86 } else {
87 None
88 }
89 })
90 .cloned()
91 .collect::<Vec<_>>();
92
93 for ident in idents {
94 self = self.merge_choice_cardinality(ident).unwrap();
95 }
96
97 self
98 }
99}