From ece23903d1713f815b5ef4223460c9b0d2cee40b Mon Sep 17 00:00:00 2001 From: Kenny Kerr Date: Tue, 13 Feb 2024 10:17:27 -0600 Subject: [PATCH] Metadata generation of attributes and constants (#2844) --- .gitignore | 1 - crates/libs/bindgen/src/rdl/to_winmd.rs | 4 +- crates/libs/bindgen/src/winmd/from_reader.rs | 80 ++++++++++++- crates/libs/bindgen/src/winmd/writer/codes.rs | 112 +++++++++--------- crates/libs/bindgen/src/winmd/writer/mod.rs | 46 ++++--- .../libs/bindgen/src/winmd/writer/tables.rs | 51 ++++---- crates/libs/metadata/src/lib.rs | 1 + crates/libs/metadata/src/tables.rs | 19 ++- crates/tools/riddle/src/main.rs | 4 +- 9 files changed, 203 insertions(+), 115 deletions(-) diff --git a/.gitignore b/.gitignore index be7c0e6cfa..4c6fca839a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,5 @@ /.vscode /.vs /target -/temp *.lock *.winmd diff --git a/crates/libs/bindgen/src/rdl/to_winmd.rs b/crates/libs/bindgen/src/rdl/to_winmd.rs index efb2321168..2cdb6bab16 100644 --- a/crates/libs/bindgen/src/rdl/to_winmd.rs +++ b/crates/libs/bindgen/src/rdl/to_winmd.rs @@ -70,7 +70,7 @@ fn write_interface(writer: &mut winmd::Writer, namespace: &str, name: &str, memb } writer.tables.TypeDef.push(winmd::TypeDef { - Extends: 0, + Extends: winmd::TypeDefOrRef::none(), FieldList: writer.tables.Field.len() as u32, MethodList: writer.tables.MethodDef.len() as u32, Flags: flags.0, @@ -82,7 +82,7 @@ fn write_interface(writer: &mut winmd::Writer, namespace: &str, name: &str, memb writer.tables.GenericParam.push(writer::GenericParam { Number: number as u16, Flags: 0, - Owner: writer::TypeOrMethodDef::TypeDef(writer.tables.TypeDef.len() as u32 - 1).encode(), + Owner: writer::TypeOrMethodDef::TypeDef(writer.tables.TypeDef.len() as u32 - 1), Name: writer.strings.insert(generic), }); } diff --git a/crates/libs/bindgen/src/winmd/from_reader.rs b/crates/libs/bindgen/src/winmd/from_reader.rs index 5771568257..534c35ecc3 100644 --- a/crates/libs/bindgen/src/winmd/from_reader.rs +++ b/crates/libs/bindgen/src/winmd/from_reader.rs @@ -1,4 +1,5 @@ use super::*; +use metadata::{AsRow, HasAttributes}; pub fn from_reader(reader: &metadata::Reader, config: std::collections::BTreeMap<&str, &str>, output: &str) -> Result<()> { let mut writer = Writer::new(output); @@ -22,7 +23,7 @@ pub fn from_reader(reader: &metadata::Reader, config: std::collections::BTreeMap let generics = &metadata::type_def_generics(def); - let extends = if let Some(extends) = def.extends() { writer.insert_type_ref(extends.namespace, extends.name) } else { 0 }; + let extends = if let Some(extends) = def.extends() { writer.insert_type_ref(extends.namespace, extends.name) } else { TypeDefOrRef::none() }; writer.tables.TypeDef.push(TypeDef { Extends: extends, @@ -33,11 +34,13 @@ pub fn from_reader(reader: &metadata::Reader, config: std::collections::BTreeMap TypeNamespace: writer.strings.insert(def.namespace()), }); + let def_ref = writer.tables.TypeDef.len() as u32 - 1; + for generic in def.generics() { writer.tables.GenericParam.push(GenericParam { Number: generic.number(), // TODO: isn't this just going to be incremental? Flags: 0, - Owner: TypeOrMethodDef::TypeDef(writer.tables.TypeDef.len() as u32 - 1).encode(), + Owner: TypeOrMethodDef::TypeDef(def_ref), Name: writer.strings.insert(generic.name()), }); } @@ -53,7 +56,7 @@ pub fn from_reader(reader: &metadata::Reader, config: std::collections::BTreeMap rest => unimplemented!("{rest:?}"), }; - writer.tables.InterfaceImpl.push(InterfaceImpl { Class: writer.tables.TypeDef.len() as u32 - 1, Interface: reference }); + writer.tables.InterfaceImpl.push(InterfaceImpl { Class: def_ref, Interface: reference }); } // TODO: if the class is "Apis" then should we sort the fields (constants) and methods (functions) for stability @@ -63,6 +66,10 @@ pub fn from_reader(reader: &metadata::Reader, config: std::collections::BTreeMap let signature = writer.insert_field_sig(&ty); writer.tables.Field.push(Field { Flags: field.flags().0, Name: writer.strings.insert(field.name()), Signature: signature }); + + if let Some(constant) = field.constant() { + writer.tables.Constant.push(Constant { Type: constant.usize(0) as u16, Parent: HasConstant::Field(writer.tables.Field.len() as u32 - 1), Value: writer.blobs.insert(&constant.blob(2)) }) + } } for method in def.methods() { @@ -85,6 +92,44 @@ pub fn from_reader(reader: &metadata::Reader, config: std::collections::BTreeMap writer.tables.Param.push(Param { Flags: param.flags().0, Sequence: param.sequence(), Name: writer.strings.insert(param.name()) }); } } + + for attribute in def.attributes() { + let metadata::AttributeType::MemberRef(attribute_ctor) = attribute.ty(); + assert_eq!(attribute_ctor.name(), ".ctor"); + let metadata::MemberRefParent::TypeRef(attribute_type) = attribute_ctor.parent(); + + let attribute_type_ref = if let TypeDefOrRef::TypeRef(type_ref) = writer.insert_type_ref(attribute_type.namespace(), attribute_type.name()) { MemberRefParent::TypeRef(type_ref) } else { panic!() }; + + let signature = attribute_ctor.signature(); + let return_type = winmd_type(&signature.return_type); + let param_types: Vec = signature.params.iter().map(winmd_type).collect(); + let signature = writer.insert_method_sig(signature.call_flags, &return_type, ¶m_types); + + writer.tables.MemberRef.push(MemberRef { Class: attribute_type_ref, Name: writer.strings.insert(".ctor"), Signature: signature }); + + let mut values = 1u16.to_le_bytes().to_vec(); // prolog + let args = attribute.args(); + let mut named_arg_count = false; + + for (index, (name, value)) in args.iter().enumerate() { + value_blob(value, &mut values); + + if !named_arg_count && !name.is_empty() { + named_arg_count = true; + let named_arg_count = (args.len() - index) as u16; + values.extend_from_slice(&named_arg_count.to_le_bytes()); + break; + } + } + + if !named_arg_count { + values.extend_from_slice(&0u16.to_le_bytes()); + } + + let values = writer.blobs.insert(&values); + + writer.tables.CustomAttribute.push(CustomAttribute { Parent: HasAttribute::TypeDef(def_ref), Type: AttributeType::MemberRef(writer.tables.MemberRef.len() as u32 - 1), Value: values }); + } } // TODO: In theory, `config` could instruct this function to balance the types across a number of winmd files @@ -92,6 +137,35 @@ pub fn from_reader(reader: &metadata::Reader, config: std::collections::BTreeMap write_to_file(output, writer.into_stream()).map_err(|err| err.with_path(output)) } +// TODO: need a Blob type for writing +fn value_blob(value: &metadata::Value, blob: &mut Vec) { + match value { + metadata::Value::Bool(value) => { + if *value { + blob.push(1) + } else { + blob.push(0) + } + } + metadata::Value::U32(value) => blob.extend_from_slice(&value.to_le_bytes()), + metadata::Value::I32(value) => blob.extend_from_slice(&value.to_le_bytes()), + metadata::Value::U16(value) => blob.extend_from_slice(&value.to_le_bytes()), + metadata::Value::U8(value) => blob.extend_from_slice(&value.to_le_bytes()), + metadata::Value::EnumDef(_def, value) => value_blob(value, blob), + + metadata::Value::TypeName(value) => { + let value = value.to_string(); + usize_blob(value.len(), blob); + blob.extend_from_slice(value.as_bytes()); + } + metadata::Value::String(value) => { + usize_blob(value.len(), blob); + blob.extend_from_slice(value.as_bytes()); + } + rest => unimplemented!("{rest:?}"), + } +} + // TODO: keep the basic type conversion fn winmd_type(ty: &metadata::Type) -> Type { match ty { diff --git a/crates/libs/bindgen/src/winmd/writer/codes.rs b/crates/libs/bindgen/src/winmd/writer/codes.rs index c5aa789e0a..16e2565c52 100644 --- a/crates/libs/bindgen/src/winmd/writer/codes.rs +++ b/crates/libs/bindgen/src/winmd/writer/codes.rs @@ -1,71 +1,69 @@ #![allow(dead_code, clippy::enum_variant_names)] -/// A `ResolutionScope` is an index into a certain table indicating the scope in which a TypeRef can be resolved. -#[derive(Clone)] -pub enum ResolutionScope { - Module(u32), - ModuleRef(u32), - AssemblyRef(u32), - TypeRef(u32), -} - -impl ResolutionScope { - pub fn encode(&self) -> u32 { - match self { - Self::Module(row) => (row + 1) << 2, - Self::ModuleRef(row) => ((row + 1) << 2) + 1, - Self::AssemblyRef(row) => ((row + 1) << 2) + 2, - Self::TypeRef(row) => ((row + 1) << 2) + 3, +macro_rules! code { + ($name:ident($size:literal) $(($table:ident, $code:literal))+) => { + #[derive(Clone, Copy)] + pub enum $name { + $($table(u32),)* } - } + impl $name { + pub fn encode(&self) -> u32 { + match self { + $(Self::$table(row) => (row.overflowing_add(1).0) << $size | $code,)* + } + } + } + }; } -/// A `TypeDefOrRef` is an index into a certain table used to locate a type definition. -#[derive(Clone)] -pub enum TypeDefOrRef { - TypeDef(u32), - TypeRef(u32), - TypeSpec(u32), +code! { AttributeType(3) + (MemberRef, 3) +} + +// TODO: needs to be called HasCustomAttribute +code! { HasAttribute(5) + (MethodDef, 0) + (Field, 1) + (TypeRef, 2) + (TypeDef, 3) + (Param, 4) + (InterfaceImpl, 5) + (MemberRef, 6) + (TypeSpec, 13) + (GenericParam, 19) +} + +code! { HasConstant(2) + (Field, 0) +} + +code! { MemberForwarded(1) + (MethodDef, 1) +} + +code! { MemberRefParent(3) + (TypeRef, 1) +} + +code! { TypeDefOrRef(2) + (TypeDef, 0) + (TypeRef, 1) + (TypeSpec, 2) } impl TypeDefOrRef { - pub fn encode(&self) -> u32 { - match self { - Self::TypeDef(row) => (row + 1) << 2, - Self::TypeRef(row) => ((row + 1) << 2) + 1, - Self::TypeSpec(row) => ((row + 1) << 2) + 2, - } + pub fn none() -> Self { + TypeDefOrRef::TypeDef(u32::MAX) } } -/// A `HasConstant` is an index into a certain table used to identify the parent of a row in the `Constant` table. -#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)] -pub enum HasConstant { - Field(u32), - Param(u32), - Property(u32), +code! { TypeOrMethodDef(1) + (TypeDef, 0) } -impl HasConstant { - pub fn encode(&self) -> u32 { - match self { - Self::Field(row) => (row + 1) << 2, - Self::Param(row) => ((row + 1) << 2) + 1, - Self::Property(row) => ((row + 1) << 2) + 2, - } - } -} - -/// A `TypeOrMethodDef` is an index into a certain table used to locate the owner of a generic parameter. -#[derive(Clone)] -pub enum TypeOrMethodDef { - TypeDef(u32), -} - -impl TypeOrMethodDef { - pub fn encode(&self) -> u32 { - match self { - Self::TypeDef(row) => (row + 1) << 1, - } - } +code! { ResolutionScope(2) + (Module, 0) + (ModuleRef, 1) + (AssemblyRef, 2) + (TypeRef, 3) } diff --git a/crates/libs/bindgen/src/winmd/writer/mod.rs b/crates/libs/bindgen/src/winmd/writer/mod.rs index 7ac4a08d61..1ad0086db3 100644 --- a/crates/libs/bindgen/src/winmd/writer/mod.rs +++ b/crates/libs/bindgen/src/winmd/writer/mod.rs @@ -19,10 +19,10 @@ pub struct Writer { pub blobs: Blobs, pub strings: Strings, pub tables: Tables, - pub scopes: HashMap, + pub scopes: HashMap, // TODO: is this faster than jsut using a single HashMap with a (String,String) key? - pub type_refs: HashMap>, - pub type_specs: HashMap, + pub type_refs: HashMap>, + pub type_specs: HashMap, } impl Writer { @@ -36,7 +36,7 @@ impl Writer { type_specs: Default::default(), }; - writer.tables.TypeDef.push(TypeDef { TypeName: writer.strings.insert(""), ..Default::default() }); + writer.tables.TypeDef.push(TypeDef { TypeName: writer.strings.insert(""), Flags: 0, TypeNamespace: 0, Extends: TypeDefOrRef::none(), FieldList: 0, MethodList: 0 }); let name = name.rsplit_once(&['/', '\\']).map_or(name, |(_, name)| name); @@ -88,7 +88,7 @@ impl Writer { self.blobs.insert(&blob) } - fn insert_scope(&mut self, namespace: &str) -> u32 { + fn insert_scope(&mut self, namespace: &str) -> ResolutionScope { if let Some(scope) = self.scopes.get(namespace) { *scope } else if namespace == "System" { @@ -97,8 +97,7 @@ impl Writer { MajorVersion: 4, PublicKeyOrToken: self.blobs.insert(&[0xB7, 0x7A, 0x5C, 0x56, 0x19, 0x34, 0xE0, 0x89]), // TODO: comment on this ..Default::default() - })) - .encode(); + })); self.scopes.insert(namespace.to_string(), scope); scope } else { @@ -111,14 +110,13 @@ impl Writer { RevisionNumber: 0xFF, Flags: metadata::AssemblyFlags::WindowsRuntime.0, ..Default::default() - })) - .encode(); + })); self.scopes.insert(namespace.to_string(), scope); scope } } - pub fn insert_type_ref(&mut self, namespace: &str, name: &str) -> u32 { + pub fn insert_type_ref(&mut self, namespace: &str, name: &str) -> TypeDefOrRef { if let Some(key) = self.type_refs.get(namespace) { if let Some(reference) = key.get(name) { return *reference; @@ -127,12 +125,12 @@ impl Writer { let scope = self.insert_scope(namespace); - let reference = TypeDefOrRef::TypeRef(self.tables.TypeRef.push2(TypeRef { TypeName: self.strings.insert(name), TypeNamespace: self.strings.insert(namespace), ResolutionScope: scope })).encode(); + let reference = TypeDefOrRef::TypeRef(self.tables.TypeRef.push2(TypeRef { TypeName: self.strings.insert(name), TypeNamespace: self.strings.insert(namespace), ResolutionScope: scope })); self.type_refs.entry(namespace.to_string()).or_default().insert(name.to_string(), reference); reference } - pub fn insert_type_spec(&mut self, ty: Type) -> u32 { + pub fn insert_type_spec(&mut self, ty: Type) -> TypeDefOrRef { if let Some(key) = self.type_specs.get(&ty) { return *key; } @@ -141,8 +139,7 @@ impl Writer { self.type_blob(&ty, &mut blob); let signature = self.blobs.insert(&blob); - let reference = TypeDefOrRef::TypeSpec(self.tables.TypeSpec.push2(TypeSpec { Signature: signature })).encode(); - + let reference = TypeDefOrRef::TypeSpec(self.tables.TypeSpec.push2(TypeSpec { Signature: signature })); self.type_specs.insert(ty, reference); reference } @@ -169,12 +166,12 @@ impl Writer { Type::GUID => { let code = self.insert_type_ref("System", "Guid"); blob.push(metadata::ELEMENT_TYPE_VALUETYPE); - usize_blob(code as usize, blob); + usize_blob(code.encode() as usize, blob); } Type::HRESULT => { let code = self.insert_type_ref("Windows.Foundation", "HResult"); blob.push(metadata::ELEMENT_TYPE_VALUETYPE); - usize_blob(code as usize, blob); + usize_blob(code.encode() as usize, blob); } Type::TypeRef(ty) => { if !ty.generics.is_empty() { @@ -182,7 +179,7 @@ impl Writer { } let code = self.insert_type_ref(&ty.namespace, &ty.name); blob.push(metadata::ELEMENT_TYPE_VALUETYPE); - usize_blob(code as usize, blob); + usize_blob(code.encode() as usize, blob); if !ty.generics.is_empty() { usize_blob(ty.generics.len(), blob); @@ -195,26 +192,26 @@ impl Writer { Type::BSTR => { let code = self.insert_type_ref("Windows.Win32.Foundation", "BSTR"); blob.push(metadata::ELEMENT_TYPE_VALUETYPE); - usize_blob(code as usize, blob); + usize_blob(code.encode() as usize, blob); } Type::IUnknown => { let code = self.insert_type_ref("Windows.Win32.Foundation", "IUnknown"); blob.push(metadata::ELEMENT_TYPE_VALUETYPE); - usize_blob(code as usize, blob); + usize_blob(code.encode() as usize, blob); } Type::PCWSTR | Type::PWSTR => { let code = self.insert_type_ref("Windows.Win32.Foundation", "PWSTR"); blob.push(metadata::ELEMENT_TYPE_VALUETYPE); - usize_blob(code as usize, blob); + usize_blob(code.encode() as usize, blob); } Type::PCSTR | Type::PSTR => { let code = self.insert_type_ref("Windows.Win32.Foundation", "PSTR"); blob.push(metadata::ELEMENT_TYPE_VALUETYPE); - usize_blob(code as usize, blob); + usize_blob(code.encode() as usize, blob); } Type::ConstRef(ty) => { usize_blob(metadata::ELEMENT_TYPE_CMOD_OPT as usize, blob); - usize_blob(self.insert_type_ref("System.Runtime.CompilerServices", "IsConst") as usize, blob); + usize_blob(self.insert_type_ref("System.Runtime.CompilerServices", "IsConst").encode() as usize, blob); usize_blob(metadata::ELEMENT_TYPE_BYREF as usize, blob); self.type_blob(ty, blob); } @@ -237,7 +234,7 @@ impl Writer { Type::Type => { let code = self.insert_type_ref("System", "Type"); blob.push(metadata::ELEMENT_TYPE_CLASS); - usize_blob(code as usize, blob); + usize_blob(code.encode() as usize, blob); } Type::MutPtr(ty, pointers) | Type::ConstPtr(ty, pointers) => { for _ in 0..*pointers { @@ -258,7 +255,8 @@ fn round(size: usize, round: usize) -> usize { (size + round) & !round } -fn usize_blob(value: usize, blob: &mut Vec) { +// TODO: need a Blob type for writing +pub fn usize_blob(value: usize, blob: &mut Vec) { // See II.23.2 in ECMA-335 assert!(value < 0x20000000); diff --git a/crates/libs/bindgen/src/winmd/writer/tables.rs b/crates/libs/bindgen/src/winmd/writer/tables.rs index df31abd41c..474f9cce8d 100644 --- a/crates/libs/bindgen/src/winmd/writer/tables.rs +++ b/crates/libs/bindgen/src/winmd/writer/tables.rs @@ -60,17 +60,15 @@ pub struct ClassLayout { pub Parent: u32, } -#[derive(Default)] pub struct Constant { pub Type: u16, - pub Parent: u32, + pub Parent: HasConstant, pub Value: u32, } -#[derive(Default)] pub struct CustomAttribute { - pub Parent: u32, - pub Type: u32, + pub Parent: HasAttribute, + pub Type: AttributeType, pub Value: u32, } @@ -81,11 +79,10 @@ pub struct Field { pub Signature: u32, } -#[derive(Default)] pub struct GenericParam { pub Number: u16, pub Flags: u16, - pub Owner: u32, + pub Owner: TypeOrMethodDef, pub Name: u32, } @@ -97,15 +94,13 @@ pub struct ImplMap { pub ImportScope: u32, } -#[derive(Default)] pub struct InterfaceImpl { pub Class: u32, - pub Interface: u32, + pub Interface: TypeDefOrRef, } -#[derive(Default)] pub struct MemberRef { - pub Class: u32, + pub Class: MemberRefParent, pub Name: u32, pub Signature: u32, } @@ -154,19 +149,17 @@ pub struct Property { pub Type: u32, } -#[derive(Default)] pub struct TypeDef { pub Flags: u32, pub TypeName: u32, pub TypeNamespace: u32, - pub Extends: u32, + pub Extends: TypeDefOrRef, pub FieldList: u32, pub MethodList: u32, } -#[derive(Default)] pub struct TypeRef { - pub ResolutionScope: u32, + pub ResolutionScope: ResolutionScope, pub TypeName: u32, pub TypeNamespace: u32, } @@ -183,12 +176,12 @@ impl Tables { } let resolution_scope = metadata::coded_index_size(&[self.Module.len(), self.ModuleRef.len(), self.AssemblyRef.len(), self.TypeRef.len()]); - let type_def_or_ref = metadata::coded_index_size(&[self.TypeDef.len(), self.TypeRef.len(), self.TypeSpec.len()]); - let has_constant = metadata::coded_index_size(&[self.Field.len(), self.Param.len(), self.Property.len()]); - let type_or_method_def = metadata::coded_index_size(&[self.TypeDef.len(), self.MethodDef.len()]); + let member_ref_parent = metadata::coded_index_size(&[self.TypeDef.len(), self.TypeRef.len(), self.ModuleRef.len(), self.MethodDef.len(), self.TypeSpec.len()]); + let custom_attribute_type = metadata::coded_index_size(&[self.MethodDef.len(), self.MemberRef.len(), 0, 0, 0]); + let has_custom_attribute = metadata::coded_index_size(&[self.MethodDef.len(), self.Field.len(), self.TypeRef.len(), self.TypeDef.len(), self.Param.len(), self.InterfaceImpl.len(), self.MemberRef.len(), self.Module.len(), 0, 0, 0, self.ModuleRef.len(), self.TypeSpec.len(), 0, self.AssemblyRef.len(), 0, 0, 0, self.GenericParam.len(), 0, 0]); let valid_tables: u64 = 1 << 0 | // Module 1 << 0x01 | // TypeRef @@ -254,7 +247,7 @@ impl Tables { } for x in self.TypeRef { - buffer.write_code(x.ResolutionScope, resolution_scope); + buffer.write_code(x.ResolutionScope.encode(), resolution_scope); buffer.write_u32(x.TypeName); buffer.write_u32(x.TypeNamespace); } @@ -263,7 +256,7 @@ impl Tables { buffer.write_u32(x.Flags); buffer.write_u32(x.TypeName); buffer.write_u32(x.TypeNamespace); - buffer.write_code(x.Extends, type_def_or_ref); + buffer.write_code(x.Extends.encode(), type_def_or_ref); buffer.write_index(x.FieldList, self.Field.len()); buffer.write_index(x.MethodList, self.MethodDef.len()); } @@ -291,12 +284,24 @@ impl Tables { for x in self.InterfaceImpl { buffer.write_index(x.Class, self.TypeDef.len()); - buffer.write_code(x.Interface, type_def_or_ref); + buffer.write_code(x.Interface.encode(), type_def_or_ref); + } + + for x in self.MemberRef { + buffer.write_code(x.Class.encode(), member_ref_parent); + buffer.write_u32(x.Name); + buffer.write_u32(x.Signature); } for x in self.Constant { buffer.write_u16(x.Type); - buffer.write_code(x.Parent, has_constant); + buffer.write_code(x.Parent.encode(), has_constant); + buffer.write_u32(x.Value); + } + + for x in self.CustomAttribute { + buffer.write_code(x.Parent.encode(), has_custom_attribute); + buffer.write_code(x.Type.encode(), custom_attribute_type); buffer.write_u32(x.Value); } @@ -331,7 +336,7 @@ impl Tables { for x in self.GenericParam { buffer.write_u16(x.Number); buffer.write_u16(x.Flags); - buffer.write_code(x.Owner, type_or_method_def); + buffer.write_code(x.Owner.encode(), type_or_method_def); buffer.write_u32(x.Name); } diff --git a/crates/libs/metadata/src/lib.rs b/crates/libs/metadata/src/lib.rs index 1b3d959cc1..870be4c649 100644 --- a/crates/libs/metadata/src/lib.rs +++ b/crates/libs/metadata/src/lib.rs @@ -97,6 +97,7 @@ pub enum Value { EnumDef(TypeDef, Box), } +#[derive(Debug)] pub struct MethodDefSig { pub call_flags: MethodCallAttributes, pub return_type: Type, diff --git a/crates/libs/metadata/src/tables.rs b/crates/libs/metadata/src/tables.rs index d7e3ad6086..15c1bf745b 100644 --- a/crates/libs/metadata/src/tables.rs +++ b/crates/libs/metadata/src/tables.rs @@ -63,10 +63,13 @@ impl Attribute { let AttributeType::MemberRef(member) = self.ty(); let mut sig = member.blob(2); let mut values = self.blob(2); - let _prolog = values.read_u16(); - let _this_and_gen_param_count = sig.read_usize(); + let prolog = values.read_u16(); + std::debug_assert_eq!(prolog, 1); + let this_and_gen_param_count = sig.read_usize(); + std::debug_assert_eq!(this_and_gen_param_count, 32); let fixed_arg_count = sig.read_usize(); - let _ret_type = sig.read_usize(); + let ret_type = sig.read_usize(); + std::debug_assert_eq!(ret_type, 1); let mut args = Vec::with_capacity(fixed_arg_count); let reader = self.reader(); @@ -219,6 +222,16 @@ impl MemberRef { pub fn name(&self) -> &'static str { self.str(1) } + + pub fn signature(&self) -> MethodDefSig { + let reader = self.reader(); + let mut blob = self.blob(2); + let call_flags = MethodCallAttributes(blob.read_usize() as u8); + let params = blob.read_usize(); + let return_type = reader.type_from_blob(&mut blob, None, &[]); + + MethodDefSig { call_flags, return_type, params: (0..params).map(|_| reader.type_from_blob(&mut blob, None, &[])).collect() } + } } impl MethodDef { diff --git a/crates/tools/riddle/src/main.rs b/crates/tools/riddle/src/main.rs index 1794dfa95f..65185952a0 100644 --- a/crates/tools/riddle/src/main.rs +++ b/crates/tools/riddle/src/main.rs @@ -16,9 +16,9 @@ Options: ); } else { match windows_bindgen::bindgen(args) { - Ok(ok) => println!("{}", ok), + Ok(ok) => println!("{ok}"), Err(error) => { - eprintln!("{}", error); + eprintln!("{error}"); std::process::exit(1); } }