1use super::*;
2
3#[derive(Clone)]
4pub enum Item {
5 Type(TypeDef),
6 Const(Field),
7 // TODO: get rid of the trailing String - that's just a hack to get around a silly Win32 metadata deficiency where parsing method signatures
8 // requires knowing which namespace the method's surrounding interface was defined in.
9 Fn(MethodDef, &'static str),
10}
11
12pub struct Reader {
13 // TODO: get rid of inner Vec - that's just a hack to support multi-arch structs in Win32 metadata.
14 items: BTreeMap<&'static str, BTreeMap<&'static str, Vec<Item>>>,
15
16 // TODO: riddle should just avoid nested structs
17 nested: HashMap<TypeDef, BTreeMap<&'static str, TypeDef>>,
18
19 // The reader needs to store the filter since standalone code generation needs more than just the filtered items
20 // in order to chase dependencies automatically. This is why `Reader::filter` can't just filter everything up front.
21 filter: Filter,
22}
23
24impl Reader {
25 pub fn new(files: Vec<File>) -> &'static Self {
26 Self::filter(files, &[], &[])
27 }
28
29 pub fn filter(files: Vec<File>, include: &[&str], exclude: &[&str]) -> &'static Self {
30 let reader: &'static mut Reader = Box::leak(Box::new(Self { items: Default::default(), nested: Default::default(), filter: Filter::new(include, exclude) }));
31
32 for mut file in files {
33 file.reader = reader as *mut Reader;
34 let file = Box::leak(Box::new(file));
35
36 for def in file.table::<TypeDef>() {
37 let namespace = def.namespace();
38
39 if namespace.is_empty() {
40 continue;
41 }
42
43 let namespace_items = reader.items.entry(namespace).or_default();
44 let name = def.name();
45
46 if name == "Apis" {
47 for method in def.methods() {
48 namespace_items.entry(method.name()).or_default().push(Item::Fn(method, namespace));
49 }
50
51 for field in def.fields() {
52 namespace_items.entry(field.name()).or_default().push(Item::Const(field));
53 }
54 } else {
55 namespace_items.entry(name).or_default().push(Item::Type(def));
56
57 // TODO: these should all be fields on the Apis class so we don't have to go looking for all of these as well.
58 if def.extends() == Some(TypeName::Enum) && !def.flags().contains(TypeAttributes::WindowsRuntime) && !def.has_attribute("ScopedEnumAttribute") {
59 for field in def.fields().filter(|field| field.flags().contains(FieldAttributes::Literal)) {
60 namespace_items.entry(field.name()).or_default().push(Item::Const(field));
61 }
62 }
63 }
64 }
65
66 for key in file.table::<NestedClass>() {
67 let inner = key.inner();
68 reader.nested.entry(key.outer()).or_default().insert(inner.name(), inner);
69 }
70 }
71
72 reader
73 }
74
75 pub fn includes_namespace(&self, namespace: &str) -> bool {
76 self.filter.includes_namespace(namespace)
77 }
78
79 pub fn namespaces(&self) -> impl Iterator<Item = &str> + '_ {
80 self.items.keys().copied()
81 }
82
83 pub fn items(&self) -> impl Iterator<Item = Item> + '_ {
84 self.items.iter().filter(move |(namespace, _)| self.filter.includes_namespace(namespace)).flat_map(move |(namespace, items)| items.iter().filter(move |(name, _)| self.filter.includes_type_name(namespace, name))).flat_map(move |(_, items)| items).cloned()
85 }
86
87 pub fn namespace_items(&self, namespace: &str) -> impl Iterator<Item = Item> + '_ {
88 self.items.get_key_value(namespace).into_iter().flat_map(move |(namespace, items)| items.iter().filter(move |(name, _)| self.filter.includes_type_name(namespace, name))).flat_map(move |(_, items)| items).cloned()
89 }
90
91 pub fn unused(&self) -> impl Iterator<Item = &str> + '_ {
92 self.filter.0.iter().filter_map(|(name, _)| if self.is_unused(name) { Some(name.as_str()) } else { None })
93 }
94
95 fn is_unused(&self, filter: &str) -> bool {
96 // Match namespaces
97 if self.items.contains_key(filter) {
98 return false;
99 }
100
101 // Match type names
102 if let Some((namespace, name)) = filter.rsplit_once('.') {
103 if self.items.get(namespace).is_some_and(|items| items.contains_key(name)) {
104 return false;
105 }
106 }
107
108 // Match empty parent namespaces
109 for namespace in self.items.keys() {
110 if namespace.len() > filter.len() && namespace.starts_with(filter) && namespace.as_bytes()[filter.len()] == b'.' {
111 return false;
112 }
113 }
114
115 true
116 }
117
118 fn get_item(&self, namespace: &str, name: &str) -> impl Iterator<Item = Item> + '_ {
119 if let Some(items) = self.items.get(namespace) {
120 if let Some(items) = items.get(name) {
121 return Some(items.iter().cloned()).into_iter().flatten();
122 }
123 }
124 None.into_iter().flatten()
125 }
126
127 pub fn get_type_def(&self, namespace: &str, name: &str) -> impl Iterator<Item = TypeDef> + '_ {
128 self.get_item(namespace, name).filter_map(|item| if let Item::Type(def) = item { Some(def) } else { None })
129 }
130
131 pub fn get_method_def(&self, namespace: &str, name: &str) -> impl Iterator<Item = (MethodDef, &'static str)> + '_ {
132 self.get_item(namespace, name).filter_map(|item| if let Item::Fn(def, namespace) = item { Some((def, namespace)) } else { None })
133 }
134
135 pub fn nested_types(&self, type_def: TypeDef) -> impl Iterator<Item = TypeDef> + '_ {
136 self.nested.get(&type_def).map(|map| map.values().copied()).into_iter().flatten()
137 }
138
139 pub fn type_from_ref(&self, code: TypeDefOrRef, enclosing: Option<TypeDef>, generics: &[Type]) -> Type {
140 if let TypeDefOrRef::TypeSpec(def) = code {
141 let mut blob = def.blob(0);
142 return self.type_from_blob_impl(&mut blob, None, generics);
143 }
144
145 let mut full_name = code.type_name();
146
147 // TODO: remove this
148 for (known_name, kind) in CORE_TYPES {
149 if full_name == known_name {
150 return kind;
151 }
152 }
153
154 // TODO: remove this
155 for (from, to) in REMAP_TYPES {
156 if full_name == from {
157 full_name = to;
158 break;
159 }
160 }
161
162 if let Some(outer) = enclosing {
163 if full_name.namespace.is_empty() {
164 let nested = &self.nested[&outer];
165 let Some(inner) = nested.get(full_name.name) else {
166 panic!("Nested type not found: {}.{}", outer.type_name(), full_name.name);
167 };
168 return Type::TypeDef(*inner, Vec::new());
169 }
170 }
171
172 if let Some(def) = self.get_type_def(full_name.namespace, full_name.name).next() {
173 Type::TypeDef(def, Vec::new())
174 } else {
175 Type::TypeRef(full_name)
176 }
177 }
178
179 pub fn type_from_blob(&self, blob: &mut Blob, enclosing: Option<TypeDef>, generics: &[Type]) -> Type {
180 // Used by WinRT to indicate that a struct input parameter is passed by reference rather than by value on the ABI.
181 let is_const = blob.read_modifiers().iter().any(|def| def.type_name() == TypeName::IsConst);
182
183 // Used by WinRT to indicate an output parameter, but there are other ways to determine this direction so here
184 // it is only used to distinguish between slices and heap-allocated arrays.
185 let is_ref = blob.read_expected(ELEMENT_TYPE_BYREF as usize);
186
187 if blob.read_expected(ELEMENT_TYPE_VOID as usize) {
188 return Type::Void;
189 }
190
191 let is_array = blob.read_expected(ELEMENT_TYPE_SZARRAY as usize); // Used by WinRT to indicate an array
192
193 let mut pointers = 0;
194
195 while blob.read_expected(ELEMENT_TYPE_PTR as usize) {
196 pointers += 1;
197 }
198
199 let kind = self.type_from_blob_impl(blob, enclosing, generics);
200
201 if pointers > 0 {
202 Type::MutPtr(Box::new(kind), pointers)
203 } else if is_const {
204 Type::ConstRef(Box::new(kind))
205 } else if is_array {
206 if is_ref {
207 Type::WinrtArrayRef(Box::new(kind))
208 } else {
209 Type::WinrtArray(Box::new(kind))
210 }
211 } else {
212 kind
213 }
214 }
215
216 fn type_from_blob_impl(&self, blob: &mut Blob, enclosing: Option<TypeDef>, generics: &[Type]) -> Type {
217 let code = blob.read_usize();
218
219 if let Some(code) = Type::from_code(code) {
220 return code;
221 }
222
223 match code as u8 {
224 ELEMENT_TYPE_VALUETYPE | ELEMENT_TYPE_CLASS => self.type_from_ref(TypeDefOrRef::decode(blob.file, blob.read_usize()), enclosing, generics),
225 ELEMENT_TYPE_VAR => generics.get(blob.read_usize()).unwrap_or(&Type::Void).clone(),
226 ELEMENT_TYPE_ARRAY => {
227 let kind = self.type_from_blob(blob, enclosing, generics);
228 let _rank = blob.read_usize();
229 let _count = blob.read_usize();
230 let bounds = blob.read_usize();
231 Type::Win32Array(Box::new(kind), bounds)
232 }
233 ELEMENT_TYPE_GENERICINST => {
234 blob.read_usize(); // ELEMENT_TYPE_VALUETYPE or ELEMENT_TYPE_CLASS
235
236 let type_name = TypeDefOrRef::decode(blob.file, blob.read_usize()).type_name();
237 let def = self.get_type_def(type_name.namespace, type_name.name).next().unwrap_or_else(|| panic!("Type not found: {}", type_name));
238 let mut args = Vec::with_capacity(blob.read_usize());
239
240 for _ in 0..args.capacity() {
241 args.push(self.type_from_blob_impl(blob, enclosing, generics));
242 }
243
244 Type::TypeDef(def, args)
245 }
246 rest => unimplemented!("{rest:?}"),
247 }
248 }
249}
250
251// TODO: this should be in riddle's Rust generator if at all - perhaps as convertible types rather than remapped types since there's already some precedent for that.
252pub const REMAP_TYPES: [(TypeName, TypeName); 2] = [(TypeName::D2D_MATRIX_3X2_F, TypeName::Matrix3x2), (TypeName::D3DMATRIX, TypeName::Matrix4x4)];
253
254// TODO: get rid of at least the second tuple if not the whole thing.
255pub const CORE_TYPES: [(TypeName, Type); 11] = [(TypeName::GUID, Type::GUID), (TypeName::IUnknown, Type::IUnknown), (TypeName::HResult, Type::HRESULT), (TypeName::HRESULT, Type::HRESULT), (TypeName::HSTRING, Type::String), (TypeName::BSTR, Type::BSTR), (TypeName::IInspectable, Type::IInspectable), (TypeName::PSTR, Type::PSTR), (TypeName::PWSTR, Type::PWSTR), (TypeName::Type, Type::Type), (TypeName::CHAR, Type::U8)];
256