diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-30 18:31:44 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-30 18:31:44 +0000 |
commit | c23a457e72abe608715ac76f076f47dc42af07a5 (patch) | |
tree | 2772049aaf84b5c9d0ed12ec8d86812f7a7904b6 /vendor/windows-bindgen/src/winmd | |
parent | Releasing progress-linux version 1.73.0+dfsg1-1~progress7.99u1. (diff) | |
download | rustc-c23a457e72abe608715ac76f076f47dc42af07a5.tar.xz rustc-c23a457e72abe608715ac76f076f47dc42af07a5.zip |
Merging upstream version 1.74.1+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/windows-bindgen/src/winmd')
-rw-r--r-- | vendor/windows-bindgen/src/winmd/from_reader.rs | 141 | ||||
-rw-r--r-- | vendor/windows-bindgen/src/winmd/mod.rs | 7 | ||||
-rw-r--r-- | vendor/windows-bindgen/src/winmd/verify.rs | 31 | ||||
-rw-r--r-- | vendor/windows-bindgen/src/winmd/writer/blobs.rs | 48 | ||||
-rw-r--r-- | vendor/windows-bindgen/src/winmd/writer/codes.rs | 71 | ||||
-rw-r--r-- | vendor/windows-bindgen/src/winmd/writer/file.rs | 134 | ||||
-rw-r--r-- | vendor/windows-bindgen/src/winmd/writer/mod.rs | 329 | ||||
-rw-r--r-- | vendor/windows-bindgen/src/winmd/writer/strings.rs | 35 | ||||
-rw-r--r-- | vendor/windows-bindgen/src/winmd/writer/tables.rs | 361 | ||||
-rw-r--r-- | vendor/windows-bindgen/src/winmd/writer/traits.rs | 66 | ||||
-rw-r--r-- | vendor/windows-bindgen/src/winmd/writer/type.rs | 80 |
11 files changed, 1303 insertions, 0 deletions
diff --git a/vendor/windows-bindgen/src/winmd/from_reader.rs b/vendor/windows-bindgen/src/winmd/from_reader.rs new file mode 100644 index 000000000..b535caed0 --- /dev/null +++ b/vendor/windows-bindgen/src/winmd/from_reader.rs @@ -0,0 +1,141 @@ +use super::*; +use crate::winmd::{self, writer}; +use metadata::RowReader; + +pub fn from_reader(reader: &metadata::Reader, filter: &metadata::Filter, config: std::collections::BTreeMap<&str, &str>, output: &str) -> crate::Result<()> { + let mut writer = winmd::Writer::new(output); + + // TODO: do we need any configuration values for winmd generation? + // Maybe per-namespace winmd files for namespace-splitting - be sure to use + // the same key as for winmd generation. + + if let Some((key, _)) = config.first_key_value() { + return Err(crate::Error::new(&format!("invalid configuration value `{key}`"))); + } + + // TODO: just use the reader directly since we now have everything in the reader, there's no need to abstract + // away the source format. Few reprs is always better. + + for item in reader.items(filter) { + // TODO: cover all variants + let metadata::Item::Type(def) = item else { + continue; + }; + + let generics = &metadata::type_def_generics(reader, def); + + let extends = if let Some(extends) = reader.type_def_extends(def) { writer.insert_type_ref(extends.namespace, extends.name) } else { 0 }; + + writer.tables.TypeDef.push(writer::TypeDef { + Extends: extends, + FieldList: writer.tables.Field.len() as u32, + Flags: reader.type_def_flags(def).0, + MethodList: writer.tables.MethodDef.len() as u32, + TypeName: writer.strings.insert(reader.type_def_name(def)), + TypeNamespace: writer.strings.insert(reader.type_def_namespace(def)), + }); + + for generic in reader.type_def_generics(def) { + writer.tables.GenericParam.push(writer::GenericParam { + Number: reader.generic_param_number(generic), + Flags: 0, + Owner: writer::TypeOrMethodDef::TypeDef(writer.tables.TypeDef.len() as u32 - 1).encode(), + Name: writer.strings.insert(reader.generic_param_name(generic)), + }); + } + + for imp in reader.type_def_interface_impls(def) { + let ty = reader.interface_impl_type(imp, generics); + let ty = winmd_type(reader, &ty); + + let reference = match &ty { + winmd::Type::TypeRef(type_name) if type_name.generics.is_empty() => writer.insert_type_ref(&type_name.namespace, &type_name.name), + winmd::Type::TypeRef(_) => writer.insert_type_spec(ty), + winmd::Type::IUnknown => writer.insert_type_ref("Windows.Win32.System.Com", "IUnknown"), + winmd::Type::IInspectable => writer.insert_type_ref("Windows.Win32.System.WinRT", "IInspectable"), + rest => unimplemented!("{rest:?}"), + }; + + writer.tables.InterfaceImpl.push(writer::InterfaceImpl { Class: writer.tables.TypeDef.len() as u32 - 1, Interface: reference }); + } + + // TODO: if the class is "Apis" then should we sort the fields (constants) and methods (functions) for stability + + for field in reader.type_def_fields(def) { + let ty = winmd_type(reader, &reader.field_type(field, Some(def))); + let signature = writer.insert_field_sig(&ty); + + writer.tables.Field.push(writer::Field { Flags: reader.field_flags(field).0, Name: writer.strings.insert(reader.field_name(field)), Signature: signature }); + } + + for method in reader.type_def_methods(def) { + let signature = reader.method_def_signature(method, generics); + let return_type = winmd_type(reader, &signature.return_type); + let param_types: Vec<Type> = signature.params.iter().map(|param| winmd_type(reader, param)).collect(); + + let signature = writer.insert_method_sig(signature.call_flags, &return_type, ¶m_types); + + writer.tables.MethodDef.push(winmd::MethodDef { + RVA: 0, + ImplFlags: reader.method_def_impl_flags(method).0, + Flags: reader.method_def_flags(method).0, + Name: writer.strings.insert(reader.method_def_name(method)), + Signature: signature, + ParamList: writer.tables.Param.len() as u32, + }); + + for param in reader.method_def_params(method) { + writer.tables.Param.push(writer::Param { Flags: reader.param_flags(param).0, Sequence: reader.param_sequence(param), Name: writer.strings.insert(reader.param_name(param)) }); + } + } + } + + // TODO: In theory, `config` could instruct this function to balance the types across a number of winmd files + // like mdmerge supports for namespace-splitting. + crate::write_to_file(output, writer.into_stream()).map_err(|err| err.with_path(output)) +} + +// TODO: keep the basic type conversion +fn winmd_type(reader: &metadata::Reader, ty: &metadata::Type) -> winmd::Type { + match ty { + metadata::Type::Void => winmd::Type::Void, + metadata::Type::Bool => winmd::Type::Bool, + metadata::Type::Char => winmd::Type::Char, + metadata::Type::I8 => winmd::Type::I8, + metadata::Type::U8 => winmd::Type::U8, + metadata::Type::I16 => winmd::Type::I16, + metadata::Type::U16 => winmd::Type::U16, + metadata::Type::I32 => winmd::Type::I32, + metadata::Type::U32 => winmd::Type::U32, + metadata::Type::I64 => winmd::Type::I64, + metadata::Type::U64 => winmd::Type::U64, + metadata::Type::F32 => winmd::Type::F32, + metadata::Type::F64 => winmd::Type::F64, + metadata::Type::ISize => winmd::Type::ISize, + metadata::Type::USize => winmd::Type::USize, + metadata::Type::String => winmd::Type::String, + metadata::Type::GUID => winmd::Type::GUID, + metadata::Type::IUnknown => winmd::Type::IUnknown, + metadata::Type::IInspectable => winmd::Type::IInspectable, + metadata::Type::HRESULT => winmd::Type::HRESULT, + metadata::Type::PSTR => winmd::Type::PSTR, + metadata::Type::PWSTR => winmd::Type::PWSTR, + metadata::Type::PCSTR => winmd::Type::PCSTR, + metadata::Type::PCWSTR => winmd::Type::PCWSTR, + metadata::Type::BSTR => winmd::Type::BSTR, + metadata::Type::TypeName => winmd::Type::TypeName, + metadata::Type::TypeDef(def, generics) => winmd::Type::TypeRef(winmd::TypeName { + namespace: reader.type_def_namespace(*def).to_string(), + name: reader.type_def_name(*def).to_string(), + generics: generics.iter().map(|ty| winmd_type(reader, ty)).collect(), + }), + metadata::Type::GenericParam(generic) => winmd::Type::GenericParam(reader.generic_param_number(*generic)), + metadata::Type::ConstRef(ty) => winmd::Type::ConstRef(Box::new(winmd_type(reader, ty))), + metadata::Type::WinrtArrayRef(ty) => winmd::Type::WinrtArrayRef(Box::new(winmd_type(reader, ty))), + metadata::Type::WinrtArray(ty) => winmd::Type::WinrtArray(Box::new(winmd_type(reader, ty))), + metadata::Type::MutPtr(ty, pointers) => winmd::Type::MutPtr(Box::new(winmd_type(reader, ty)), *pointers), + metadata::Type::ConstPtr(ty, pointers) => winmd::Type::ConstPtr(Box::new(winmd_type(reader, ty)), *pointers), + metadata::Type::Win32Array(ty, len) => winmd::Type::Win32Array(Box::new(winmd_type(reader, ty)), *len), + rest => unimplemented!("{rest:?}"), + } +} diff --git a/vendor/windows-bindgen/src/winmd/mod.rs b/vendor/windows-bindgen/src/winmd/mod.rs new file mode 100644 index 000000000..f01afa218 --- /dev/null +++ b/vendor/windows-bindgen/src/winmd/mod.rs @@ -0,0 +1,7 @@ +mod from_reader; +mod verify; +pub mod writer; +use super::*; +pub use from_reader::from_reader; +pub use verify::verify; +pub use writer::*; diff --git a/vendor/windows-bindgen/src/winmd/verify.rs b/vendor/windows-bindgen/src/winmd/verify.rs new file mode 100644 index 000000000..f10bd6524 --- /dev/null +++ b/vendor/windows-bindgen/src/winmd/verify.rs @@ -0,0 +1,31 @@ +use super::*; +use metadata::RowReader; + +pub fn verify(reader: &metadata::Reader, filter: &metadata::Filter) -> crate::Result<()> { + for item in reader.items(filter) { + // TODO: cover all variants + let metadata::Item::Type(def) = item else { + continue; + }; + + let generics = &metadata::type_def_generics(reader, def); + + reader.type_def_fields(def).try_for_each(|field| not_type_ref(reader, &reader.field_type(field, Some(def))))?; + + reader.type_def_methods(def).try_for_each(|method| { + let sig = reader.method_def_signature(method, generics); + not_type_ref(reader, &sig.return_type)?; + + sig.params.iter().try_for_each(|param| not_type_ref(reader, param)) + })?; + } + + Ok(()) +} + +fn not_type_ref(reader: &metadata::Reader, ty: &metadata::Type) -> crate::Result<()> { + if let metadata::Type::TypeRef(ty) = ty { + return Err(crate::Error::new(&format!("missing type definition `{}`", reader.type_def_or_ref(*ty)))); + } + Ok(()) +} diff --git a/vendor/windows-bindgen/src/winmd/writer/blobs.rs b/vendor/windows-bindgen/src/winmd/writer/blobs.rs new file mode 100644 index 000000000..5201a32d0 --- /dev/null +++ b/vendor/windows-bindgen/src/winmd/writer/blobs.rs @@ -0,0 +1,48 @@ +use super::*; +use std::collections::hash_map::*; + +pub struct Blobs { + map: HashMap<Vec<u8>, u32>, + stream: Vec<u8>, +} + +impl Default for Blobs { + fn default() -> Self { + Self { map: Default::default(), stream: vec![0] } + } +} + +impl Blobs { + pub fn insert(&mut self, value: &[u8]) -> u32 { + if value.is_empty() { + return 0; + } + + match self.map.entry(value.to_vec()) { + Entry::Vacant(entry) => { + let offset = *entry.insert(self.stream.len() as u32); + let len = value.len(); + match len { + 0..=0x7F => self.stream.push(len as u8), + 0x80..=0x3FFF => { + self.stream.push((0x80 | len >> 8) as u8); + self.stream.push((0xFF & len) as u8); + } + _ => { + self.stream.push((0xC0 | len >> 24) as u8); + self.stream.push((0xFF & len >> 16) as u8); + self.stream.push((0xFF & len >> 8) as u8); + self.stream.push((0xFF & len) as u8); + } + } + self.stream.extend_from_slice(value); + offset + } + Entry::Occupied(entry) => *entry.get(), + } + } + + pub fn into_stream(self) -> Vec<u8> { + self.stream.into_stream() + } +} diff --git a/vendor/windows-bindgen/src/winmd/writer/codes.rs b/vendor/windows-bindgen/src/winmd/writer/codes.rs new file mode 100644 index 000000000..c5aa789e0 --- /dev/null +++ b/vendor/windows-bindgen/src/winmd/writer/codes.rs @@ -0,0 +1,71 @@ +#![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, + } + } +} + +/// 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), +} + +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, + } + } +} + +/// 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), +} + +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, + } + } +} diff --git a/vendor/windows-bindgen/src/winmd/writer/file.rs b/vendor/windows-bindgen/src/winmd/writer/file.rs new file mode 100644 index 000000000..b452ba559 --- /dev/null +++ b/vendor/windows-bindgen/src/winmd/writer/file.rs @@ -0,0 +1,134 @@ +use super::*; +use metadata::imp::*; +use std::mem::*; + +pub fn write(mut tables: Vec<u8>, mut strings: Vec<u8>, mut blobs: Vec<u8>) -> Vec<u8> { + if [tables.len(), strings.len(), blobs.len()].iter().any(|len| *len > u32::MAX as usize) { + panic!("heap too large"); + } + + unsafe { + let mut guids = vec![0; 16]; // zero guid + let size_of_streams = tables.len() + guids.len() + strings.len() + blobs.len(); + + let mut dos: IMAGE_DOS_HEADER = zeroed(); + dos.e_magic = IMAGE_DOS_SIGNATURE; + dos.e_lfarlc = 64; + dos.e_lfanew = size_of::<IMAGE_DOS_HEADER>() as i32; + + let mut file: IMAGE_FILE_HEADER = zeroed(); + file.Machine = IMAGE_FILE_MACHINE_I386; + file.NumberOfSections = 1; + file.SizeOfOptionalHeader = size_of::<IMAGE_OPTIONAL_HEADER32>() as u16; + file.Characteristics = IMAGE_FILE_DLL | IMAGE_FILE_32BIT_MACHINE | IMAGE_FILE_EXECUTABLE_IMAGE; + + let mut optional: IMAGE_OPTIONAL_HEADER32 = zeroed(); + optional.Magic = IMAGE_NT_OPTIONAL_HDR32_MAGIC; + optional.MajorLinkerVersion = 11; + optional.SizeOfInitializedData = 1024; + optional.ImageBase = 0x400000; + optional.SectionAlignment = SECTION_ALIGNMENT; + optional.FileAlignment = 512; + optional.MajorOperatingSystemVersion = 6; + optional.MinorOperatingSystemVersion = 2; + optional.MajorSubsystemVersion = 6; + optional.MinorSubsystemVersion = 2; + optional.SizeOfHeaders = 512; + optional.Subsystem = IMAGE_SUBSYSTEM_WINDOWS_CUI; + optional.DllCharacteristics = IMAGE_DLLCHARACTERISTICS_NX_COMPAT | IMAGE_DLLCHARACTERISTICS_NO_SEH | IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE; + optional.SizeOfStackReserve = 0x100000; + optional.SizeOfHeapReserve = 4096; + optional.LoaderFlags = 0x100000; + optional.NumberOfRvaAndSizes = 16; + + let mut section: IMAGE_SECTION_HEADER = zeroed(); + section.Name = *b".text\0\0\0"; + section.Characteristics = 0x4000_0020; + section.VirtualAddress = SECTION_ALIGNMENT; + + let mut clr: IMAGE_COR20_HEADER = zeroed(); + clr.cb = size_of::<IMAGE_COR20_HEADER>() as u32; + clr.MajorRuntimeVersion = 2; + clr.MinorRuntimeVersion = 5; + clr.Flags = 1; + + let metadata = METADATA_HEADER { + signature: METADATA_SIGNATURE, + major_version: 1, + minor_version: 1, + length: 20, + version: *b"WindowsRuntime 1.4\0\0", + streams: 4, + ..Default::default() + }; + + type TablesHeader = StreamHeader<4>; + type StringsHeader = StreamHeader<12>; + type GuidsHeader = StreamHeader<8>; + type BlobsHeader = StreamHeader<8>; + + let size_of_stream_headers = size_of::<TablesHeader>() + size_of::<StringsHeader>() + size_of::<GuidsHeader>() + size_of::<BlobsHeader>(); + let size_of_image = optional.FileAlignment as usize + size_of::<IMAGE_COR20_HEADER>() + size_of::<METADATA_HEADER>() + size_of_stream_headers + size_of_streams; + + optional.SizeOfImage = round(size_of_image, optional.SectionAlignment as usize) as u32; + section.Misc.VirtualSize = size_of_image as u32 - optional.FileAlignment; + section.SizeOfRawData = round(section.Misc.VirtualSize as usize, optional.FileAlignment as usize) as u32; + + optional.DataDirectory[14] = IMAGE_DATA_DIRECTORY { VirtualAddress: SECTION_ALIGNMENT, Size: size_of::<IMAGE_COR20_HEADER>() as u32 }; + section.PointerToRawData = optional.FileAlignment; + clr.MetaData.VirtualAddress = SECTION_ALIGNMENT + size_of::<IMAGE_COR20_HEADER>() as u32; + clr.MetaData.Size = section.Misc.VirtualSize - size_of::<IMAGE_COR20_HEADER>() as u32; + + let mut buffer = Vec::<u8>::new(); + + buffer.write_header(&dos); + buffer.write_u32(IMAGE_NT_SIGNATURE); + buffer.write_header(&file); + buffer.write_header(&optional); + buffer.write_header(§ion); + debug_assert!(buffer.len() < optional.FileAlignment as usize); + buffer.resize(optional.FileAlignment as usize, 0); + buffer.write_header(&clr); + let metadata_offset = buffer.len(); + buffer.write_header(&metadata); + + let stream_offset = buffer.len() - metadata_offset + size_of_stream_headers; + let tables_header = TablesHeader::new(stream_offset as u32, tables.len() as u32, b"#~\0\0"); + let strings_header = StringsHeader::new(tables_header.next_offset(), strings.len() as u32, b"#Strings\0\0\0\0"); + let guids_header = GuidsHeader::new(strings_header.next_offset(), guids.len() as u32, b"#GUID\0\0\0"); + let blobs_header = BlobsHeader::new(guids_header.next_offset(), blobs.len() as u32, b"#Blob\0\0\0"); + + buffer.write_header(&tables_header); + buffer.write_header(&strings_header); + buffer.write_header(&guids_header); + buffer.write_header(&blobs_header); + + buffer.append(&mut tables); + buffer.append(&mut strings); + buffer.append(&mut guids); + buffer.append(&mut blobs); + + assert_eq!(clr.MetaData.Size as usize, buffer.len() - metadata_offset); + assert_eq!(size_of_image, buffer.len()); + + buffer + } +} + +const SECTION_ALIGNMENT: u32 = 4096; + +#[repr(C)] +struct StreamHeader<const LEN: usize> { + offset: u32, + size: u32, + name: [u8; LEN], +} + +impl<const LEN: usize> StreamHeader<LEN> { + fn new(offset: u32, size: u32, name: &[u8; LEN]) -> Self { + Self { offset, size, name: *name } + } + fn next_offset(&self) -> u32 { + self.offset + self.size + } +} diff --git a/vendor/windows-bindgen/src/winmd/writer/mod.rs b/vendor/windows-bindgen/src/winmd/writer/mod.rs new file mode 100644 index 000000000..af49ecfeb --- /dev/null +++ b/vendor/windows-bindgen/src/winmd/writer/mod.rs @@ -0,0 +1,329 @@ +mod blobs; +mod codes; +mod file; +mod strings; +mod tables; +mod traits; +mod r#type; + +use super::*; +use blobs::Blobs; +pub use codes::*; +use metadata::imp::*; +pub use r#type::*; +use std::collections::HashMap; +use strings::Strings; +pub use tables::*; +use traits::*; + +pub struct Writer { + pub blobs: Blobs, + pub strings: Strings, + pub tables: Tables, + pub scopes: HashMap<String, u32>, + // TODO: is this faster than jsut using a single HashMap with a (String,String) key? + pub type_refs: HashMap<String, HashMap<String, u32>>, + pub type_specs: HashMap<Type, u32>, +} + +impl Writer { + pub fn new(name: &str) -> Self { + let mut writer = Self { + blobs: Default::default(), + strings: Default::default(), + tables: Default::default(), + scopes: Default::default(), + type_refs: Default::default(), + type_specs: Default::default(), + }; + + writer.tables.TypeDef.push(TypeDef { TypeName: writer.strings.insert("<Module>"), ..Default::default() }); + + let name = name.rsplit_once(&['/', '\\']).map_or(name, |(_, name)| name); + + writer.tables.Module.push(Module { Name: writer.strings.insert(name), Mvid: 1, ..Default::default() }); + + let name = name.rsplit_once('.').map_or(name, |(_, name)| name); + + writer.tables.Assembly.push(Assembly { + Name: writer.strings.insert(name), + HashAlgId: 0x00008004, + MajorVersion: 0xFF, + MinorVersion: 0xFF, + BuildNumber: 0xFF, + RevisionNumber: 0xFF, + Flags: metadata::AssemblyFlags::WindowsRuntime.0, + ..Default::default() + }); + + // Some winmd parsers will fail to read without an `mscorlib` reference. The `insert_module_types` function will typically include it + // automatically but a minimal `Module` tree may not add this dependency. + writer.insert_scope("System"); + + writer + } + + pub fn into_stream(self) -> Vec<u8> { + file::write(self.tables.into_stream(), self.strings.into_stream(), self.blobs.into_stream()) + } + + pub fn insert_method_sig(&mut self, call_flags: metadata::MethodCallAttributes, return_type: &Type, param_types: &[Type]) -> u32 { + let mut blob = vec![call_flags.0]; + usize_blob(param_types.len(), &mut blob); + self.type_blob(return_type, &mut blob); + + for ty in param_types { + self.type_blob(ty, &mut blob); + } + + self.blobs.insert(&blob) + } + + pub fn insert_field_sig(&mut self, ty: &Type) -> u32 { + // TODO: can either cache in Writer, like we do for scopes and type_refs, or regenerate each time. + // Profile once we can stress test this with field/method signatures. + + let mut blob = vec![0x6]; // FIELD + self.type_blob(ty, &mut blob); + + self.blobs.insert(&blob) + } + + fn insert_scope(&mut self, namespace: &str) -> u32 { + if let Some(scope) = self.scopes.get(namespace) { + *scope + } else if namespace == "System" { + let scope = ResolutionScope::AssemblyRef(self.tables.AssemblyRef.push2(AssemblyRef { + Name: self.strings.insert("mscorlib"), + 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 { + // TODO: may need to capture the original assembly info for external type_refs. + let scope = ResolutionScope::AssemblyRef(self.tables.AssemblyRef.push2(AssemblyRef { + Name: self.strings.insert(namespace), + MajorVersion: 0xFF, + MinorVersion: 0xFF, + BuildNumber: 0xFF, + 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 { + if let Some(key) = self.type_refs.get(namespace) { + if let Some(reference) = key.get(name) { + return *reference; + } + } + + 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(); + 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 { + if let Some(key) = self.type_specs.get(&ty) { + return *key; + } + + let mut blob = vec![]; + self.type_blob(&ty, &mut blob); + let signature = self.blobs.insert(&blob); + + let reference = TypeDefOrRef::TypeSpec(self.tables.TypeSpec.push2(TypeSpec { Signature: signature })).encode(); + + self.type_specs.insert(ty, reference); + reference + } + + fn type_blob(&mut self, ty: &Type, blob: &mut Vec<u8>) { + match ty { + Type::Void => blob.push(ELEMENT_TYPE_VOID), + Type::Bool => blob.push(ELEMENT_TYPE_BOOLEAN), + Type::Char => blob.push(ELEMENT_TYPE_CHAR), + Type::I8 => blob.push(ELEMENT_TYPE_I1), + Type::U8 => blob.push(ELEMENT_TYPE_U1), + Type::I16 => blob.push(ELEMENT_TYPE_I2), + Type::U16 => blob.push(ELEMENT_TYPE_U2), + Type::I32 => blob.push(ELEMENT_TYPE_I4), + Type::U32 => blob.push(ELEMENT_TYPE_U4), + Type::I64 => blob.push(ELEMENT_TYPE_I8), + Type::U64 => blob.push(ELEMENT_TYPE_U8), + Type::F32 => blob.push(ELEMENT_TYPE_R4), + Type::F64 => blob.push(ELEMENT_TYPE_R8), + Type::ISize => blob.push(ELEMENT_TYPE_I), + Type::USize => blob.push(ELEMENT_TYPE_U), + Type::String => blob.push(ELEMENT_TYPE_STRING), + Type::IInspectable => blob.push(ELEMENT_TYPE_OBJECT), + Type::GUID => { + let code = self.insert_type_ref("System", "Guid"); + blob.push(ELEMENT_TYPE_VALUETYPE); + usize_blob(code as usize, blob); + } + Type::HRESULT => { + let code = self.insert_type_ref("Windows.Foundation", "HResult"); + blob.push(ELEMENT_TYPE_VALUETYPE); + usize_blob(code as usize, blob); + } + Type::TypeRef(ty) => { + if !ty.generics.is_empty() { + blob.push(ELEMENT_TYPE_GENERICINST); + } + let code = self.insert_type_ref(&ty.namespace, &ty.name); + blob.push(ELEMENT_TYPE_VALUETYPE); + usize_blob(code as usize, blob); + + if !ty.generics.is_empty() { + usize_blob(ty.generics.len(), blob); + + for ty in &ty.generics { + self.type_blob(ty, blob); + } + } + } + Type::BSTR => { + let code = self.insert_type_ref("Windows.Win32.Foundation", "BSTR"); + blob.push(ELEMENT_TYPE_VALUETYPE); + usize_blob(code as usize, blob); + } + Type::IUnknown => { + let code = self.insert_type_ref("Windows.Win32.Foundation", "IUnknown"); + blob.push(ELEMENT_TYPE_VALUETYPE); + usize_blob(code as usize, blob); + } + Type::PCWSTR | Type::PWSTR => { + let code = self.insert_type_ref("Windows.Win32.Foundation", "PWSTR"); + blob.push(ELEMENT_TYPE_VALUETYPE); + usize_blob(code as usize, blob); + } + Type::PCSTR | Type::PSTR => { + let code = self.insert_type_ref("Windows.Win32.Foundation", "PSTR"); + blob.push(ELEMENT_TYPE_VALUETYPE); + usize_blob(code as usize, blob); + } + Type::ConstRef(ty) => { + usize_blob(ELEMENT_TYPE_CMOD_OPT as usize, blob); + usize_blob(self.insert_type_ref("System.Runtime.CompilerServices", "IsConst") as usize, blob); + usize_blob(ELEMENT_TYPE_BYREF as usize, blob); + self.type_blob(ty, blob); + } + Type::WinrtArrayRef(ty) => { + usize_blob(ELEMENT_TYPE_BYREF as usize, blob); + usize_blob(ELEMENT_TYPE_SZARRAY as usize, blob); + self.type_blob(ty, blob); + } + Type::WinrtArray(ty) => { + usize_blob(ELEMENT_TYPE_SZARRAY as usize, blob); + self.type_blob(ty, blob); + } + Type::Win32Array(ty, bounds) => { + usize_blob(ELEMENT_TYPE_ARRAY as usize, blob); + self.type_blob(ty, blob); + usize_blob(1, blob); // rank + usize_blob(1, blob); // count + usize_blob(*bounds, blob); + } + Type::TypeName => { + let code = self.insert_type_ref("System", "Type"); + blob.push(ELEMENT_TYPE_CLASS); + usize_blob(code as usize, blob); + } + Type::MutPtr(ty, pointers) | Type::ConstPtr(ty, pointers) => { + for _ in 0..*pointers { + usize_blob(ELEMENT_TYPE_PTR as usize, blob); + } + self.type_blob(ty, blob); + } + Type::GenericParam(index) => { + blob.push(ELEMENT_TYPE_VAR); + usize_blob(*index as usize, blob); + } + } + } +} + +fn round(size: usize, round: usize) -> usize { + let round = round - 1; + (size + round) & !round +} + +fn usize_blob(value: usize, blob: &mut Vec<u8>) { + // See II.23.2 in ECMA-335 + assert!(value < 0x20000000); + + if value < 0x80 { + blob.push(value as u8); + } else if value < 0x4000 { + blob.push((0x80 | (value & 0x3F00) >> 8) as u8); + blob.push((value & 0xFF) as u8); + } else { + blob.push((0xC0 | (value & 0x1F000000) >> 24) as u8); + blob.push(((value & 0xFF0000) >> 16) as u8); + blob.push(((value & 0xFF00) >> 8) as u8); + blob.push((value & 0xFF) as u8); + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_usize_blob() { + let mut blob = vec![]; + usize_blob(0, &mut blob); + usize_blob(1, &mut blob); + usize_blob(2, &mut blob); + + usize_blob(0x80 - 2, &mut blob); + usize_blob(0x80 - 1, &mut blob); + usize_blob(0x80, &mut blob); + usize_blob(0x80 + 1, &mut blob); + usize_blob(0x80 + 2, &mut blob); + + usize_blob(0x4000 - 2, &mut blob); + usize_blob(0x4000 - 1, &mut blob); + usize_blob(0x4000, &mut blob); + usize_blob(0x4000 + 1, &mut blob); + usize_blob(0x4000 + 2, &mut blob); + + usize_blob(0x20000000 - 3, &mut blob); + usize_blob(0x20000000 - 2, &mut blob); + usize_blob(0x20000000 - 1, &mut blob); + + let mut blob = metadata::Blob::new(0, &blob); + assert_eq!(blob.read_usize(), 0); + assert_eq!(blob.read_usize(), 1); + assert_eq!(blob.read_usize(), 2); + + assert_eq!(blob.read_usize(), 0x80 - 2); + assert_eq!(blob.read_usize(), 0x80 - 1); + assert_eq!(blob.read_usize(), 0x80); + assert_eq!(blob.read_usize(), 0x80 + 1); + assert_eq!(blob.read_usize(), 0x80 + 2); + + assert_eq!(blob.read_usize(), 0x4000 - 2); + assert_eq!(blob.read_usize(), 0x4000 - 1); + assert_eq!(blob.read_usize(), 0x4000); + assert_eq!(blob.read_usize(), 0x4000 + 1); + assert_eq!(blob.read_usize(), 0x4000 + 2); + + assert_eq!(blob.read_usize(), 0x20000000 - 3); + assert_eq!(blob.read_usize(), 0x20000000 - 2); + assert_eq!(blob.read_usize(), 0x20000000 - 1); + + assert_eq!(blob.slice.len(), 0); + } +} diff --git a/vendor/windows-bindgen/src/winmd/writer/strings.rs b/vendor/windows-bindgen/src/winmd/writer/strings.rs new file mode 100644 index 000000000..1eeae6d43 --- /dev/null +++ b/vendor/windows-bindgen/src/winmd/writer/strings.rs @@ -0,0 +1,35 @@ +use super::*; +use std::collections::hash_map::*; + +pub struct Strings { + map: HashMap<String, u32>, + stream: Vec<u8>, +} + +impl Default for Strings { + fn default() -> Self { + Self { map: Default::default(), stream: vec![0] } + } +} + +impl Strings { + pub fn insert(&mut self, value: &str) -> u32 { + if value.is_empty() { + return 0; + } + + match self.map.entry(value.to_string()) { + Entry::Vacant(entry) => { + let offset = *entry.insert(self.stream.len() as u32); + self.stream.extend_from_slice(value.as_bytes()); + self.stream.push(0); + offset + } + Entry::Occupied(entry) => *entry.get(), + } + } + + pub fn into_stream(self) -> Vec<u8> { + self.stream.into_stream() + } +} diff --git a/vendor/windows-bindgen/src/winmd/writer/tables.rs b/vendor/windows-bindgen/src/winmd/writer/tables.rs new file mode 100644 index 000000000..4d4b8e354 --- /dev/null +++ b/vendor/windows-bindgen/src/winmd/writer/tables.rs @@ -0,0 +1,361 @@ +#![allow(non_snake_case)] + +use super::Write; +use super::*; +use metadata::imp::coded_index_size; + +#[derive(Default)] +pub struct Tables { + // TODO: use BTreeSet for tables that have a primary key, unless they are naturally sorted. + pub Assembly: Vec<Assembly>, + pub AssemblyRef: Vec<AssemblyRef>, + pub ClassLayout: Vec<ClassLayout>, + pub Constant: Vec<Constant>, + pub CustomAttribute: Vec<CustomAttribute>, + pub Field: Vec<Field>, + pub GenericParam: Vec<GenericParam>, + pub ImplMap: Vec<ImplMap>, + pub InterfaceImpl: Vec<InterfaceImpl>, + pub MemberRef: Vec<MemberRef>, + pub MethodDef: Vec<MethodDef>, + pub Module: Vec<Module>, + pub ModuleRef: Vec<ModuleRef>, + pub NestedClass: Vec<NestedClass>, + pub Param: Vec<Param>, + pub Property: Vec<Property>, + pub TypeDef: Vec<TypeDef>, + pub TypeRef: Vec<TypeRef>, + pub TypeSpec: Vec<TypeSpec>, +} + +#[derive(Default)] +pub struct Assembly { + pub HashAlgId: u32, + pub MajorVersion: u16, + pub MinorVersion: u16, + pub BuildNumber: u16, + pub RevisionNumber: u16, + pub Flags: u32, + pub PublicKey: u32, + pub Name: u32, + pub Culture: u32, +} + +#[derive(Default)] +pub struct AssemblyRef { + pub MajorVersion: u16, + pub MinorVersion: u16, + pub BuildNumber: u16, + pub RevisionNumber: u16, + pub Flags: u32, + pub PublicKeyOrToken: u32, + pub Name: u32, + pub Culture: u32, + pub HashValue: u32, +} + +#[derive(Default)] +pub struct ClassLayout { + pub PackingSize: u16, + pub ClassSize: u32, + pub Parent: u32, +} + +#[derive(Default)] +pub struct Constant { + pub Type: u16, + pub Parent: u32, + pub Value: u32, +} + +#[derive(Default)] +pub struct CustomAttribute { + pub Parent: u32, + pub Type: u32, + pub Value: u32, +} + +#[derive(Default)] +pub struct Field { + pub Flags: u16, + pub Name: u32, + pub Signature: u32, +} + +#[derive(Default)] +pub struct GenericParam { + pub Number: u16, + pub Flags: u16, + pub Owner: u32, + pub Name: u32, +} + +#[derive(Default)] +pub struct ImplMap { + pub MappingFlags: u16, + pub MemberForwarded: u32, + pub ImportName: u32, + pub ImportScope: u32, +} + +#[derive(Default)] +pub struct InterfaceImpl { + pub Class: u32, + pub Interface: u32, +} + +#[derive(Default)] +pub struct MemberRef { + pub Class: u32, + pub Name: u32, + pub Signature: u32, +} + +#[derive(Default)] +pub struct MethodDef { + pub RVA: u32, + pub ImplFlags: u16, + pub Flags: u16, + pub Name: u32, + pub Signature: u32, + pub ParamList: u32, +} + +#[derive(Default)] +pub struct Module { + pub Generation: u16, + pub Name: u32, + pub Mvid: u32, + pub EncId: u32, + pub EncBaseId: u32, +} + +#[derive(Default)] +pub struct ModuleRef { + pub Name: u32, +} + +#[derive(Default)] +pub struct NestedClass { + pub NestedClass: u32, + pub EnclosingClass: u32, +} + +#[derive(Default)] +pub struct Param { + pub Flags: u16, + pub Sequence: u16, + pub Name: u32, +} + +#[derive(Default)] +pub struct Property { + pub Flags: u16, + pub Name: u32, + pub Type: u32, +} + +#[derive(Default)] +pub struct TypeDef { + pub Flags: u32, + pub TypeName: u32, + pub TypeNamespace: u32, + pub Extends: u32, + pub FieldList: u32, + pub MethodList: u32, +} + +#[derive(Default)] +pub struct TypeRef { + pub ResolutionScope: u32, + pub TypeName: u32, + pub TypeNamespace: u32, +} + +#[derive(Default)] +pub struct TypeSpec { + pub Signature: u32, +} + +impl Tables { + pub fn into_stream(self) -> Vec<u8> { + if [self.AssemblyRef.len(), self.ClassLayout.len(), self.Constant.len(), self.CustomAttribute.len(), self.Field.len(), self.GenericParam.len(), self.ImplMap.len(), self.InterfaceImpl.len(), self.MemberRef.len(), self.MethodDef.len(), self.Module.len(), self.ModuleRef.len(), self.NestedClass.len(), self.Param.len(), self.Property.len(), self.TypeDef.len(), self.TypeRef.len(), self.TypeSpec.len()].iter().any(|len| *len > u32::MAX as usize) { + panic!("metadata table too large"); + } + + let resolution_scope = coded_index_size(&[self.Module.len(), self.ModuleRef.len(), self.AssemblyRef.len(), self.TypeRef.len()]); + + let type_def_or_ref = coded_index_size(&[self.TypeDef.len(), self.TypeRef.len(), self.TypeSpec.len()]); + + let has_constant = coded_index_size(&[self.Field.len(), self.Param.len(), self.Property.len()]); + + let type_or_method_def = coded_index_size(&[self.TypeDef.len(), self.MethodDef.len()]); + + let valid_tables: u64 = 1 << 0 | // Module + 1 << 0x01 | // TypeRef + 1 << 0x02 | // TypeDef + 1 << 0x04 | // Field + 1 << 0x06 | // MethodDef + 1 << 0x08 | // Param + 1 << 0x09 | // InterfaceImpl + 1 << 0x0A | // MemberRef + 1 << 0x0B | // Constant + 1 << 0x0C | // CustomAttribute + 1 << 0x0F | // ClassLayout + 1 << 0x17 | // Property + 1 << 0x1A | // ModuleRef + 1 << 0x1B | // TypeSpec + 1 << 0x1C | // ImplMap + 1 << 0x20 | // Assembly + 1 << 0x23 | // AssemblyRef + 1 << 0x29 | // NestedClass + 1 << 0x2A; // GenericParam + + // The table stream header... + + let mut buffer = Vec::new(); + buffer.write_u32(0); // Reserved + buffer.write_u8(2); // MajorVersion + buffer.write_u8(0); // MinorVersion + buffer.write_u8(0b111); // HeapSizes + buffer.write_u8(0); // Reserved + buffer.write_u64(valid_tables); + buffer.write_u64(0); // Sorted + + // Followed by the length of each of the valid tables... + + buffer.write_u32(self.Module.len() as u32); + buffer.write_u32(self.TypeRef.len() as u32); + buffer.write_u32(self.TypeDef.len() as u32); + buffer.write_u32(self.Field.len() as u32); + buffer.write_u32(self.MethodDef.len() as u32); + buffer.write_u32(self.Param.len() as u32); + buffer.write_u32(self.InterfaceImpl.len() as u32); + buffer.write_u32(self.MemberRef.len() as u32); + buffer.write_u32(self.Constant.len() as u32); + buffer.write_u32(self.CustomAttribute.len() as u32); + buffer.write_u32(self.ClassLayout.len() as u32); + buffer.write_u32(self.Property.len() as u32); + buffer.write_u32(self.ModuleRef.len() as u32); + buffer.write_u32(self.TypeSpec.len() as u32); + buffer.write_u32(self.ImplMap.len() as u32); + buffer.write_u32(self.Assembly.len() as u32); + buffer.write_u32(self.AssemblyRef.len() as u32); + buffer.write_u32(self.NestedClass.len() as u32); + buffer.write_u32(self.GenericParam.len() as u32); + + // Followed by each table's rows... + + for x in self.Module { + buffer.write_u16(x.Generation); + buffer.write_u32(x.Name); + buffer.write_u32(x.Mvid); + buffer.write_u32(x.EncId); + buffer.write_u32(x.EncBaseId); + } + + for x in self.TypeRef { + buffer.write_code(x.ResolutionScope, resolution_scope); + buffer.write_u32(x.TypeName); + buffer.write_u32(x.TypeNamespace); + } + + for x in &self.TypeDef { + 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_index(x.FieldList, self.Field.len()); + buffer.write_index(x.MethodList, self.MethodDef.len()); + } + + for x in self.Field { + buffer.write_u16(x.Flags); + buffer.write_u32(x.Name); + buffer.write_u32(x.Signature); + } + + for x in self.MethodDef { + buffer.write_u32(x.RVA); + buffer.write_u16(x.ImplFlags); + buffer.write_u16(x.Flags); + buffer.write_u32(x.Name); + buffer.write_u32(x.Signature); + buffer.write_index(x.ParamList, self.Param.len()); + } + + for x in self.Param { + buffer.write_u16(x.Flags); + buffer.write_u16(x.Sequence); + buffer.write_u32(x.Name); + } + + for x in self.InterfaceImpl { + buffer.write_index(x.Class, self.TypeDef.len()); + buffer.write_code(x.Interface, type_def_or_ref); + } + + for x in self.Constant { + buffer.write_u16(x.Type); + buffer.write_code(x.Parent, has_constant); + buffer.write_u32(x.Value); + } + + for x in self.TypeSpec { + buffer.write_u32(x.Signature); + } + + for x in self.Assembly { + buffer.write_u32(x.HashAlgId); + buffer.write_u16(x.MajorVersion); + buffer.write_u16(x.MinorVersion); + buffer.write_u16(x.BuildNumber); + buffer.write_u16(x.RevisionNumber); + buffer.write_u32(x.Flags); + buffer.write_u32(x.PublicKey); + buffer.write_u32(x.Name); + buffer.write_u32(x.Culture); + } + + for x in self.AssemblyRef { + buffer.write_u16(x.MajorVersion); + buffer.write_u16(x.MinorVersion); + buffer.write_u16(x.BuildNumber); + buffer.write_u16(x.RevisionNumber); + buffer.write_u32(x.Flags); + buffer.write_u32(x.PublicKeyOrToken); + buffer.write_u32(x.Name); + buffer.write_u32(x.Culture); + buffer.write_u32(x.HashValue); + } + + 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_u32(x.Name); + } + + // TODO: sort GenericParam table prior to writing. This needs to be done for all tables with a primary index. See II.22 + + // TODO: do these get naturally sorted by virtue of how they're pushed into "tables" in type def order? + + // Table Primary Key Column + // ClassLayout Parent + // Constant Parent + // CustomAttribute Parent + // DeclSecurity Parent + // FieldLayout Field + // FieldMarshal Parent + // FieldRVA Field + // GenericParam Owner + // GenericParamConstraint Owner + // ImplMap MemberForwarded + // InterfaceImpl Class + // MethodImpl Class + // MethodSemantics Association + // NestedClass NestedClass + + buffer.into_stream() + } +} diff --git a/vendor/windows-bindgen/src/winmd/writer/traits.rs b/vendor/windows-bindgen/src/winmd/writer/traits.rs new file mode 100644 index 000000000..45304899a --- /dev/null +++ b/vendor/windows-bindgen/src/winmd/writer/traits.rs @@ -0,0 +1,66 @@ +use super::*; + +pub trait Write { + unsafe fn write_header<T: Sized>(&mut self, value: &T); + fn write_u8(&mut self, value: u8); + fn write_u16(&mut self, value: u16); + fn write_u32(&mut self, value: u32); + fn write_u64(&mut self, value: u64); + fn write_code(&mut self, value: u32, size: usize); + fn write_index(&mut self, index: u32, len: usize); + fn into_stream(self) -> Self; +} + +impl Write for Vec<u8> { + unsafe fn write_header<T: Sized>(&mut self, value: &T) { + self.extend_from_slice(std::slice::from_raw_parts(value as *const _ as _, std::mem::size_of::<T>())); + } + + fn write_u8(&mut self, value: u8) { + self.extend_from_slice(&value.to_le_bytes()); + } + + fn write_u16(&mut self, value: u16) { + self.extend_from_slice(&value.to_le_bytes()); + } + + fn write_u32(&mut self, value: u32) { + self.extend_from_slice(&value.to_le_bytes()); + } + + fn write_u64(&mut self, value: u64) { + self.extend_from_slice(&value.to_le_bytes()); + } + + fn write_code(&mut self, value: u32, size: usize) { + if size == 2 { + self.write_u16(value as u16); + } else { + self.write_u32(value); + } + } + + fn write_index(&mut self, index: u32, len: usize) { + if len < (1 << 16) { + self.write_u16(index as u16 + 1); + } else { + self.write_u32(index + 1); + } + } + + fn into_stream(mut self) -> Self { + self.resize(round(self.len(), 4), 0); + self + } +} + +pub trait Push2<T> { + fn push2(&mut self, value: T) -> u32; +} + +impl<T> Push2<T> for Vec<T> { + fn push2(&mut self, value: T) -> u32 { + self.push(value); + (self.len() - 1) as u32 + } +} diff --git a/vendor/windows-bindgen/src/winmd/writer/type.rs b/vendor/windows-bindgen/src/winmd/writer/type.rs new file mode 100644 index 000000000..3f0178654 --- /dev/null +++ b/vendor/windows-bindgen/src/winmd/writer/type.rs @@ -0,0 +1,80 @@ +#![allow(dead_code, clippy::upper_case_acronyms)] + +#[derive(Clone, Debug, Hash, PartialEq, Eq)] +pub struct TypeName { + pub namespace: String, + pub name: String, + pub generics: Vec<Type>, +} + +#[derive(Clone, Debug, Hash, PartialEq, Eq)] +pub enum Type { + Void, + Bool, + Char, + I8, + U8, + I16, + U16, + I32, + U32, + I64, + U64, + F32, + F64, + ISize, + USize, + String, + GUID, + IUnknown, + IInspectable, + HRESULT, + PSTR, + PWSTR, + PCSTR, + PCWSTR, + BSTR, + TypeName, + TypeRef(TypeName), + GenericParam(u16), + MutPtr(Box<Self>, usize), + ConstPtr(Box<Self>, usize), + Win32Array(Box<Self>, usize), + WinrtArray(Box<Self>), + WinrtArrayRef(Box<Self>), + ConstRef(Box<Self>), +} + +impl Type { + pub fn into_mut_ptr(self) -> Self { + match self { + Self::MutPtr(ty, count) => Self::MutPtr(ty, count + 1), + Self::ConstPtr(ty, count) => Self::MutPtr(ty, count + 1), + _ => Self::MutPtr(Box::new(self), 1), + } + } + + pub fn into_const_ptr(self) -> Self { + match self { + Self::MutPtr(ty, count) => Self::ConstPtr(ty, count + 1), + Self::ConstPtr(ty, count) => Self::ConstPtr(ty, count + 1), + _ => Self::ConstPtr(Box::new(self), 1), + } + } + + pub fn into_array(self, len: usize) -> Self { + Self::Win32Array(Box::new(self), len) + } +} + +pub struct Signature { + pub params: Vec<SignatureParam>, + pub return_type: Type, + pub call_flags: u8, +} + +// TODO: just Param? +pub struct SignatureParam { + pub name: String, + pub ty: Type, +} |