xsd_parser/pipeline/optimizer/
remove_duplicates.rs1use std::collections::HashMap;
2use std::hash::{Hash, Hasher};
3
4use crate::models::meta::{MetaType, MetaTypeVariant, MetaTypes, ReferenceMeta, TypeEq};
5
6use super::Optimizer;
7
8impl Optimizer {
9 #[doc = include_str!("../../../tests/optimizer/duplicate.xsd")]
29 #[doc = include_str!("../../../tests/optimizer/expected0/remove_duplicates.rs")]
34 #[doc = include_str!("../../../tests/optimizer/expected1/remove_duplicates.rs")]
39 pub fn remove_duplicates(mut self) -> Self {
41 use std::collections::hash_map::Entry;
42
43 struct Value<'a> {
44 type_: &'a MetaType,
45 types: &'a MetaTypes,
46 }
47
48 impl PartialEq for Value<'_> {
49 fn eq(&self, other: &Self) -> bool {
50 self.type_.type_eq(other.type_, self.types)
51 }
52 }
53
54 impl Eq for Value<'_> {}
55
56 impl Hash for Value<'_> {
57 fn hash<H: Hasher>(&self, state: &mut H) {
58 self.type_.type_hash(state, self.types);
59 }
60 }
61
62 tracing::debug!("remove_duplicates");
63
64 let mut changed = true;
65
66 while changed {
67 changed = false;
68
69 tracing::trace!("remove_duplicates new iteration");
70
71 let types = &self.types;
72
73 #[allow(clippy::mutable_key_type)]
74 let mut map = HashMap::new();
75 let mut idents = HashMap::new();
76
77 for (ident, type_) in &self.types.items {
78 match map.entry(Value { type_, types }) {
79 Entry::Vacant(e) => {
80 if let Some(ident) = types.get_resolved_ident(ident) {
81 e.insert(ident.clone());
82 }
83 }
84 Entry::Occupied(e) => {
85 let reference_ident = e.get();
86 if !matches!(&type_.variant, MetaTypeVariant::Reference(ti) if &ti.type_ == reference_ident)
87 {
88 idents.insert(ident.clone(), reference_ident.clone());
89 }
90 }
91 }
92 }
93
94 if !idents.is_empty() {
95 changed = true;
96 self.typedefs = None;
97 }
98
99 for (ident, referenced_type) in idents {
100 tracing::trace!(
101 "Create reference for duplicate type: {ident} => {referenced_type}"
102 );
103
104 let ty = self.types.items.get_mut(&ident).unwrap();
105 ty.variant = MetaTypeVariant::Reference(ReferenceMeta::new(referenced_type));
106 }
107 }
108
109 self
110 }
111}