1use super::*;
2
3fn insert(types: &mut HashMap<&'static str, Vec<Type>>, name: &'static str, ty: Type) {
4 types.entry(key:name).or_default().push(ty);
5}
6
7pub struct Reader(HashMap<&'static str, HashMap<&'static str, Vec<Type>>>);
8
9impl std::ops::Deref for Reader {
10 type Target = HashMap<&'static str, HashMap<&'static str, Vec<Type>>>;
11
12 fn deref(&self) -> &Self::Target {
13 &self.0
14 }
15}
16
17impl Reader {
18 pub fn new(files: Vec<File>) -> &'static Self {
19 let reader = Box::leak(Box::new(Self(HashMap::new())));
20
21 for mut file in files {
22 file.reader = reader;
23 let file = Box::leak(Box::new(file));
24 let mut nested = HashMap::<TypeDef, Vec<TypeDef>>::new();
25
26 for key in file.table::<NestedClass>() {
27 let inner = key.inner();
28 nested.entry(key.outer()).or_default().push(inner);
29 }
30
31 for def in file.table::<TypeDef>() {
32 let type_name = def.type_name();
33
34 if type_name.namespace().is_empty() {
35 // This skips the nested types as we've already retrieved them.
36 continue;
37 }
38
39 if Type::remap(type_name) != Remap::None {
40 continue;
41 }
42
43 let types = reader.0.entry(type_name.namespace()).or_default();
44 let category = Category::new(def);
45
46 if def.flags().contains(TypeAttributes::WindowsRuntime) {
47 let ty = match category {
48 Category::Attribute => continue,
49 Category::Class => Type::Class(Class { def }),
50 Category::Delegate => Type::Delegate(Delegate {
51 def,
52 generics: def.generics(),
53 }),
54 Category::Enum => Type::Enum(Enum { def }),
55 Category::Interface => Type::Interface(Interface {
56 def,
57 generics: def.generics(),
58 kind: InterfaceKind::None,
59 }),
60 Category::Struct => {
61 // Skip marker types representing API contracts.
62 if def.has_attribute("ApiContractAttribute") {
63 continue;
64 }
65
66 Type::Struct(Struct { def })
67 }
68 };
69
70 insert(types, type_name.1, ty);
71 } else {
72 match category {
73 Category::Attribute => continue,
74 Category::Class => {
75 if type_name.1 == "Apis" {
76 for method in def.methods() {
77 if let Some(map) = method.impl_map() {
78 // Skip inline and ordinal functions.
79 if map.scope().name() == "FORCEINLINE"
80 || map.import_name().starts_with("#")
81 {
82 continue;
83 }
84 }
85
86 let name = method.name();
87 insert(
88 types,
89 name,
90 Type::CppFn(CppFn {
91 namespace: def.namespace(),
92 method,
93 }),
94 );
95 }
96
97 for field in def.fields() {
98 let name = field.name();
99 insert(
100 types,
101 name,
102 Type::CppConst(CppConst {
103 namespace: def.namespace(),
104 field,
105 }),
106 );
107 }
108 }
109 }
110 Category::Delegate => {
111 insert(types, type_name.1, Type::CppDelegate(CppDelegate { def }));
112 }
113 Category::Enum => {
114 insert(types, type_name.1, Type::CppEnum(CppEnum { def }));
115
116 if !def.has_attribute("ScopedEnumAttribute") {
117 for field in def.fields() {
118 if field.flags().contains(FieldAttributes::Literal) {
119 let name = field.name();
120 insert(
121 types,
122 name,
123 Type::CppConst(CppConst {
124 namespace: def.namespace(),
125 field,
126 }),
127 );
128 }
129 }
130 }
131 }
132 Category::Interface => {
133 insert(types, type_name.1, Type::CppInterface(CppInterface { def }));
134 }
135 Category::Struct => {
136 fn make(
137 def: TypeDef,
138 name: &'static str,
139 nested: &HashMap<TypeDef, Vec<TypeDef>>,
140 ) -> CppStruct {
141 let mut ty = CppStruct {
142 def,
143 name,
144 nested: BTreeMap::new(),
145 };
146
147 for (index, def) in
148 nested.get(&def).into_iter().flatten().enumerate()
149 {
150 ty.nested.insert(
151 def.name(),
152 make(*def, format!("{}_{index}", ty.name).leak(), nested),
153 );
154 }
155
156 ty
157 }
158
159 insert(
160 types,
161 type_name.1,
162 Type::CppStruct(make(def, def.name(), &nested)),
163 );
164 }
165 };
166 }
167 }
168 }
169
170 reader
171 }
172
173 #[track_caller]
174 pub fn unwrap_full_name(&self, namespace: &str, name: &str) -> Type {
175 if let Some(ty) = self.with_full_name(namespace, name).next() {
176 ty
177 } else {
178 panic!("type not found: {namespace}.{name}")
179 }
180 }
181
182 /// Gets all types matching the given namespace and name.
183 pub fn with_full_name(&self, namespace: &str, name: &str) -> impl Iterator<Item = Type> + '_ {
184 self.get(namespace)
185 .and_then(|types| types.get(name))
186 .into_iter()
187 .flatten()
188 .cloned()
189 }
190}
191
192enum Category {
193 Interface,
194 Class,
195 Enum,
196 Struct,
197 Delegate,
198 Attribute,
199}
200
201impl Category {
202 fn new(def: TypeDef) -> Self {
203 if let Some(extends: TypeName) = def.extends() {
204 if extends.namespace() == "System" {
205 match extends.name() {
206 "Enum" => Self::Enum,
207 "MulticastDelegate" => Self::Delegate,
208 "ValueType" => Self::Struct,
209 "Attribute" => Self::Attribute,
210 _ => Self::Class,
211 }
212 } else {
213 Self::Class
214 }
215 } else {
216 Self::Interface
217 }
218 }
219}
220