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