1use super::*;
2
3#[derive(Clone, Debug, PartialEq, Eq)]
4pub struct TypeMap(HashMap<TypeName, HashSet<Type>>);
5
6impl std::ops::Deref for TypeMap {
7 type Target = HashMap<TypeName, HashSet<Type>>;
8
9 fn deref(&self) -> &Self::Target {
10 &self.0
11 }
12}
13
14impl TypeMap {
15 pub fn new() -> Self {
16 Self(HashMap::new())
17 }
18
19 pub fn filter(reader: &'static Reader, filter: &Filter, references: &References) -> Self {
20 let mut dependencies = Self::new();
21
22 for namespace in reader.keys() {
23 if filter.includes_namespace(namespace) {
24 for (name, types) in &reader[namespace] {
25 if filter.includes_type_name(TypeName(namespace, name)) {
26 let mut item_dependencies = Self::new();
27
28 for ty in types {
29 ty.dependencies(&mut item_dependencies);
30 }
31
32 if item_dependencies.excluded(filter) {
33 continue;
34 }
35
36 for ty in types {
37 dependencies.insert(ty.clone());
38 }
39
40 dependencies.combine_references(&item_dependencies, references);
41 }
42 }
43 }
44 }
45
46 dependencies
47 }
48
49 pub fn insert(&mut self, ty: Type) -> bool {
50 self.0.entry(ty.type_name()).or_default().insert(ty)
51 }
52
53 fn combine_references(&mut self, other: &Self, references: &References) {
54 for (tn, types) in &other.0 {
55 if references.contains(*tn).is_none() {
56 let set = self.0.entry(*tn).or_default();
57 types.iter().for_each(|ty| {
58 set.insert(ty.clone());
59 });
60 }
61 }
62 }
63
64 pub fn combine(&mut self, other: &Self) {
65 for (name, types) in &other.0 {
66 let set = self.0.entry(*name).or_default();
67 types.iter().for_each(|ty| {
68 set.insert(ty.clone());
69 });
70 }
71 }
72
73 pub fn difference(&self, other: &Self) -> Self {
74 Self(
75 self.0
76 .iter()
77 .filter(|(tn, _)| !other.0.contains_key(tn))
78 .map(|(tn, ty)| (*tn, ty.clone()))
79 .collect(),
80 )
81 }
82
83 pub fn included(&self, config: &Config) -> bool {
84 self.0.iter().all(|(tn, _)| {
85 // An empty namespace covers core types like `HRESULT`. This way we don't exclude methods
86 // that depend on core types that aren't explicitly included in the filter.
87 if tn.namespace().is_empty() {
88 return true;
89 }
90
91 if config.types.contains_key(tn) {
92 return true;
93 }
94
95 if config.references.contains(*tn).is_some() {
96 return true;
97 }
98
99 false
100 })
101 }
102
103 fn excluded(&self, filter: &Filter) -> bool {
104 self.0.iter().any(|(tn, _)| filter.excludes_type_name(*tn))
105 }
106}
107