1 | use super::*; |
2 | |
3 | fn insert(types: &mut HashMap<&'static str, Vec<Type>>, name: &'static str, ty: Type) { |
4 | types.entry(key:name).or_default().push(ty); |
5 | } |
6 | |
7 | pub struct Reader(HashMap<&'static str, HashMap<&'static str, Vec<Type>>>); |
8 | |
9 | impl 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 | |
17 | impl 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 | |
192 | enum Category { |
193 | Interface, |
194 | Class, |
195 | Enum, |
196 | Struct, |
197 | Delegate, |
198 | Attribute, |
199 | } |
200 | |
201 | impl 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 | |