diff --git a/crates/libs/bindgen/src/metadata.rs b/crates/libs/bindgen/src/metadata.rs index 994cba7f7b..0a0dff5b07 100644 --- a/crates/libs/bindgen/src/metadata.rs +++ b/crates/libs/bindgen/src/metadata.rs @@ -80,7 +80,7 @@ pub enum AsyncKind { pub struct Guid(pub u32, pub u16, pub u16, pub u8, pub u8, pub u8, pub u8, pub u8, pub u8, pub u8, pub u8); impl Guid { - pub fn from_args(args: &[(String, Value)]) -> Self { + pub fn from_args(args: &[(&str, Value)]) -> Self { fn unwrap_u32(value: &Value) -> u32 { match value { Value::U32(value) => *value, @@ -442,9 +442,7 @@ pub fn type_interfaces(ty: &Type) -> Vec { // This will both sort the results and should make finding dupes faster fn walk(result: &mut Vec, parent: &Type, is_base: bool) { if let Type::TypeDef(row, generics) = parent { - for imp in row.interface_impls() { - let mut child = Interface { ty: imp.ty(generics), kind: if imp.has_attribute("DefaultAttribute") { InterfaceKind::Default } else { InterfaceKind::None } }; - + for mut child in type_def_interfaces(*row, generics) { child.kind = if !is_base && child.kind == InterfaceKind::Default { InterfaceKind::Default } else if child.kind == InterfaceKind::Overridable { @@ -482,8 +480,7 @@ pub fn type_interfaces(ty: &Type) -> Vec { "StaticAttribute" | "ActivatableAttribute" => { for (_, arg) in attribute.args() { if let Value::TypeName(type_name) = arg { - let type_name = parse_type_name(&type_name); - let def = row.reader().get_type_def(type_name.0, type_name.1).next().expect("Type not found"); + let def = row.reader().get_type_def(type_name.namespace, type_name.name).next().expect("Type not found"); result.push(Interface { ty: Type::TypeDef(def, Vec::new()), kind: InterfaceKind::Static }); break; } @@ -498,7 +495,7 @@ pub fn type_interfaces(ty: &Type) -> Vec { result } -fn type_name<'a>(ty: &Type) -> &'a str { +fn type_name(ty: &Type) -> &str { match ty { Type::TypeDef(row, _) => row.name(), _ => "", @@ -657,8 +654,15 @@ pub fn type_def_has_packing(row: TypeDef) -> bool { } } +pub fn type_def_interfaces(def: TypeDef, generics: &[Type]) -> impl Iterator + '_ { + def.interface_impls().map(|imp| { + let kind = if imp.has_attribute("DefaultAttribute") { InterfaceKind::Default } else { InterfaceKind::None }; + Interface { kind, ty: imp.ty(generics) } + }) +} + pub fn type_def_default_interface(row: TypeDef) -> Option { - row.interface_impls().find_map(move |row| if row.has_attribute("DefaultAttribute") { Some(row.ty(&[])) } else { None }) + type_def_interfaces(row, &[]).find_map(move |interface| if interface.kind == InterfaceKind::Default { Some(interface.ty) } else { None }) } fn type_signature(ty: &Type) -> String { @@ -792,7 +796,7 @@ pub fn type_def_vtables(row: TypeDef) -> Vec { } } else { let mut next = row; - while let Some(base) = type_def_interfaces(next, &[]).next() { + while let Some(base) = next.interface_impls().map(move |imp| imp.ty(&[])).next() { match base { Type::TypeDef(row, _) => { next = row; @@ -813,7 +817,3 @@ pub fn type_def_vtables(row: TypeDef) -> Vec { } result } - -pub fn type_def_interfaces(row: TypeDef, generics: &[Type]) -> impl Iterator + '_ { - row.interface_impls().map(move |row| row.ty(generics)) -} diff --git a/crates/libs/bindgen/src/rdl/from_reader.rs b/crates/libs/bindgen/src/rdl/from_reader.rs index 3842614fc2..856e8a131c 100644 --- a/crates/libs/bindgen/src/rdl/from_reader.rs +++ b/crates/libs/bindgen/src/rdl/from_reader.rs @@ -3,7 +3,7 @@ use crate::tokens::{quote, to_ident, TokenStream}; use crate::{rdl, Error, Result, Tree}; use metadata::*; -pub fn from_reader(reader: &metadata::Reader, mut config: std::collections::BTreeMap<&str, &str>, output: &str) -> Result<()> { +pub fn from_reader(reader: &'static metadata::Reader, mut config: std::collections::BTreeMap<&str, &str>, output: &str) -> Result<()> { let dialect = match config.remove("type") { Some("winrt") => Dialect::WinRT, Some("win32") => Dialect::Win32, @@ -30,7 +30,7 @@ pub fn from_reader(reader: &metadata::Reader, mut config: std::collections::BTre fn gen_split(writer: &Writer) -> Result<()> { let tree = Tree::new(writer.reader); - let directory = crate::directory(writer.output); + let directory = crate::directory(&writer.output); // TODO: parallelize for tree in tree.flatten() { @@ -48,7 +48,7 @@ fn gen_split(writer: &Writer) -> Result<()> { fn gen_file(writer: &Writer) -> Result<()> { let tree = Tree::new(writer.reader); let tokens = writer.tree(&tree); - writer.write_to_file(writer.output, tokens) + writer.write_to_file(&writer.output, tokens) } #[derive(Debug, Copy, Clone, PartialEq)] @@ -57,21 +57,21 @@ enum Dialect { WinRT, } -struct Writer<'a> { - reader: &'a metadata::Reader, - namespace: &'a str, +struct Writer { + reader: &'static metadata::Reader, + namespace: &'static str, dialect: Dialect, split: bool, - output: &'a str, + output: String, } -impl<'a> Writer<'a> { - fn new(reader: &'a metadata::Reader, output: &'a str, dialect: Dialect) -> Self { - Self { reader, namespace: "", output, dialect, split: false } +impl Writer { + fn new(reader: &'static metadata::Reader, output: &str, dialect: Dialect) -> Self { + Self { reader, namespace: "", output: output.to_string(), dialect, split: false } } - fn with_namespace(&self, namespace: &'a str) -> Self { - Self { reader: self.reader, namespace, dialect: self.dialect, output: self.output, split: self.split } + fn with_namespace(&self, namespace: &'static str) -> Self { + Self { reader: self.reader, namespace, dialect: self.dialect, output: self.output.clone(), split: self.split } } fn write_to_file(&self, output: &str, tokens: TokenStream) -> Result<()> { @@ -90,7 +90,7 @@ impl<'a> Writer<'a> { //crate::write_to_file(output, tokens.into_string()) } - fn tree(&self, tree: &'a Tree) -> TokenStream { + fn tree(&self, tree: &Tree) -> TokenStream { let items = self.items(tree); if self.split { @@ -128,7 +128,7 @@ impl<'a> Writer<'a> { } } - fn items(&self, tree: &'a Tree) -> TokenStream { + fn items(&self, tree: &Tree) -> TokenStream { let mut functions = vec![]; let mut constants = vec![]; let mut types = vec![]; @@ -286,12 +286,11 @@ impl<'a> Writer<'a> { // TODO: then list default interface first // Then everything else - for imp in def.interface_impls() { - let ty = imp.ty(generics); - if imp.has_attribute("DefaultAttribute") { - types.insert(0, self.ty(&ty)); + for interface in type_def_interfaces(def, generics) { + if interface.kind == InterfaceKind::Default { + types.insert(0, self.ty(&interface.ty)); } else { - types.push(self.ty(&ty)); + types.push(self.ty(&interface.ty)); } } @@ -358,8 +357,7 @@ impl<'a> Writer<'a> { } } - metadata::Type::TypeRef(code) => { - let type_name = code.type_name(); + metadata::Type::TypeRef(type_name) => { let namespace = self.namespace(type_name.namespace); let name = to_ident(type_name.name); quote! { #namespace #name } diff --git a/crates/libs/bindgen/src/rust/cfg.rs b/crates/libs/bindgen/src/rust/cfg.rs index 59989f08a0..c1ed18553f 100644 --- a/crates/libs/bindgen/src/rust/cfg.rs +++ b/crates/libs/bindgen/src/rust/cfg.rs @@ -58,20 +58,12 @@ pub fn type_def_cfg_impl(def: TypeDef, generics: &[Type]) -> Cfg { combine(def, generics, &mut cfg); - for def in type_def_vtables(def) { - if let Type::TypeDef(def, generics) = def { + for interface in type_interfaces(&Type::TypeDef(def, generics.to_vec())) { + if let Type::TypeDef(def, generics) = interface.ty { combine(def, &generics, &mut cfg); } } - if def.flags().contains(TypeAttributes::WindowsRuntime) { - for interface in type_def_interfaces(def, generics) { - if let Type::TypeDef(def, generics) = interface { - combine(def, &generics, &mut cfg); - } - } - } - cfg_add_attributes(&mut cfg, def); cfg } @@ -156,6 +148,7 @@ pub fn type_cfg(ty: &Type) -> Cfg { type_cfg_combine(ty, &mut cfg); cfg } + fn type_cfg_combine(ty: &Type, cfg: &mut Cfg) { match ty { Type::TypeDef(row, generics) => type_def_cfg_combine(*row, generics, cfg), diff --git a/crates/libs/bindgen/src/rust/classes.rs b/crates/libs/bindgen/src/rust/classes.rs index 865b6734fb..d30cde31a2 100644 --- a/crates/libs/bindgen/src/rust/classes.rs +++ b/crates/libs/bindgen/src/rust/classes.rs @@ -2,7 +2,7 @@ use super::*; pub fn writer(writer: &Writer, def: TypeDef) -> TokenStream { if writer.sys { - if type_def_has_default_interface(def) { + if def.interface_impls().next().is_some() { let name = to_ident(def.name()); quote! { pub type #name = *mut ::core::ffi::c_void; @@ -64,7 +64,7 @@ fn gen_class(writer: &Writer, def: TypeDef) -> TokenStream { _ => None, }); - if type_def_has_default_interface(def) { + if def.interface_impls().next().is_some() { let new = if type_def_has_default_constructor(def) { quote! { pub fn new() -> ::windows_core::Result { @@ -172,10 +172,6 @@ fn type_def_has_default_constructor(row: TypeDef) -> bool { false } -fn type_def_has_default_interface(row: TypeDef) -> bool { - row.interface_impls().any(|imp| imp.has_attribute("DefaultAttribute")) -} - fn type_is_exclusive(ty: &Type) -> bool { match ty { Type::TypeDef(row, _) => type_def_is_exclusive(*row), diff --git a/crates/libs/bindgen/src/rust/mod.rs b/crates/libs/bindgen/src/rust/mod.rs index fbc3a85c71..342a6879a9 100644 --- a/crates/libs/bindgen/src/rust/mod.rs +++ b/crates/libs/bindgen/src/rust/mod.rs @@ -21,7 +21,7 @@ use crate::{Error, Result, Tree}; use cfg::*; use rayon::prelude::*; -pub fn from_reader(reader: &metadata::Reader, mut config: std::collections::BTreeMap<&str, &str>, output: &str) -> Result<()> { +pub fn from_reader(reader: &'static metadata::Reader, mut config: std::collections::BTreeMap<&str, &str>, output: &str) -> Result<()> { let mut writer = Writer::new(reader, output); writer.package = config.remove("package").is_some(); writer.flatten = config.remove("flatten").is_some(); @@ -56,7 +56,7 @@ fn gen_file(writer: &Writer) -> Result<()> { if writer.flatten { let tokens = standalone::standalone_imp(writer); - crate::write_to_file(writer.output, try_format(writer, &tokens)) + crate::write_to_file(&writer.output, try_format(writer, &tokens)) } else { let mut tokens = String::new(); let root = Tree::new(writer.reader); @@ -65,12 +65,12 @@ fn gen_file(writer: &Writer) -> Result<()> { tokens.push_str(&namespace(writer, tree)); } - crate::write_to_file(writer.output, try_format(writer, &tokens)) + crate::write_to_file(&writer.output, try_format(writer, &tokens)) } } fn gen_package(writer: &Writer) -> Result<()> { - let directory = crate::directory(writer.output); + let directory = crate::directory(&writer.output); let root = Tree::new(writer.reader); let mut root_len = 0; diff --git a/crates/libs/bindgen/src/rust/writer.rs b/crates/libs/bindgen/src/rust/writer.rs index 5145817ceb..4911244bbb 100644 --- a/crates/libs/bindgen/src/rust/writer.rs +++ b/crates/libs/bindgen/src/rust/writer.rs @@ -1,10 +1,10 @@ use super::*; #[derive(Clone)] -pub struct Writer<'a> { - pub reader: &'a Reader, - pub output: &'a str, - pub namespace: &'a str, +pub struct Writer { + pub reader: &'static Reader, + pub output: String, + pub namespace: &'static str, pub implement: bool, // TODO: ideally we can use this to generate implementation traits on the fly and // and have a single interface definition macro for consumption that expands to include // impl traits when the `implement` cfg flag is set and then this writer option would be @@ -20,11 +20,11 @@ pub struct Writer<'a> { pub no_inner_attributes: bool, // skips the inner attributes at the start of the file } -impl<'a> Writer<'a> { - pub fn new(reader: &'a Reader, output: &'a str) -> Self { +impl Writer { + pub fn new(reader: &'static Reader, output: &str) -> Self { Self { reader, - output, + output: output.to_string(), namespace: "", implement: false, std: false, @@ -403,7 +403,7 @@ impl<'a> Writer<'a> { quote! { #arch #features } } - fn cfg_features_imp(&self, cfg: &'a Cfg, namespace: &'a str) -> Vec<&'a str> { + fn cfg_features_imp(&self, cfg: &Cfg, namespace: &str) -> Vec<&'static str> { let mut compact = Vec::<&'static str>::new(); if self.package { for feature in cfg.types.keys() { @@ -568,7 +568,7 @@ impl<'a> Writer<'a> { let mut async_generics = generics.to_vec(); if kind == AsyncKind::None { - for interface in type_def_interfaces(def, generics) { + for interface in def.interface_impls().map(move |imp| imp.ty(generics)) { if let Type::TypeDef(interface_def, interface_generics) = &interface { kind = type_def_async_kind(*interface_def); if kind != AsyncKind::None { diff --git a/crates/libs/bindgen/src/tree.rs b/crates/libs/bindgen/src/tree.rs index 9fda6a302a..6a619940eb 100644 --- a/crates/libs/bindgen/src/tree.rs +++ b/crates/libs/bindgen/src/tree.rs @@ -1,13 +1,13 @@ use super::*; #[derive(Debug)] -pub struct Tree<'a> { - pub namespace: &'a str, - pub nested: std::collections::BTreeMap<&'a str, Tree<'a>>, +pub struct Tree { + pub namespace: &'static str, + pub nested: std::collections::BTreeMap<&'static str, Tree>, } -impl<'a> Tree<'a> { - pub fn new(reader: &'a metadata::Reader) -> Self { +impl Tree { + pub fn new(reader: &'static metadata::Reader) -> Self { let mut tree = Tree::from_namespace(""); for ns in reader.namespaces() { if reader.includes_namespace(ns) { @@ -17,10 +17,10 @@ impl<'a> Tree<'a> { tree } - fn from_namespace(namespace: &'a str) -> Self { + fn from_namespace(namespace: &'static str) -> Self { Self { namespace, nested: std::collections::BTreeMap::new() } } - fn insert_namespace(&mut self, namespace: &'a str, pos: usize) -> &mut Self { + fn insert_namespace(&mut self, namespace: &'static str, pos: usize) -> &mut Self { if let Some(next) = namespace[pos..].find('.') { let next = pos + next; self.nested.entry(&namespace[pos..next]).or_insert_with(|| Self::from_namespace(&namespace[..next])).insert_namespace(namespace, next + 1) diff --git a/crates/libs/bindgen/src/winmd/from_reader.rs b/crates/libs/bindgen/src/winmd/from_reader.rs index 51bc55b140..ed5f4d1783 100644 --- a/crates/libs/bindgen/src/winmd/from_reader.rs +++ b/crates/libs/bindgen/src/winmd/from_reader.rs @@ -36,16 +36,15 @@ pub fn from_reader(reader: &metadata::Reader, config: std::collections::BTreeMap for generic in def.generics() { writer.tables.GenericParam.push(writer::GenericParam { - Number: generic.number(), + Number: generic.number(), // TODO: isn't this just going to be incremental? Flags: 0, Owner: writer::TypeOrMethodDef::TypeDef(writer.tables.TypeDef.len() as u32 - 1).encode(), Name: writer.strings.insert(generic.name()), }); } - for imp in def.interface_impls() { - let ty = imp.ty(generics); - let ty = winmd_type(&ty); + for interface in metadata::type_def_interfaces(def, generics) { + let ty = winmd_type(&interface.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), @@ -122,7 +121,7 @@ fn winmd_type(ty: &metadata::Type) -> winmd::Type { 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::Type => winmd::Type::Type, metadata::Type::TypeDef(def, generics) => winmd::Type::TypeRef(winmd::TypeName { namespace: def.namespace().to_string(), name: def.name().to_string(), generics: generics.iter().map(winmd_type).collect() }), metadata::Type::GenericParam(generic) => winmd::Type::GenericParam(generic.number()), metadata::Type::ConstRef(ty) => winmd::Type::ConstRef(Box::new(winmd_type(ty))), diff --git a/crates/libs/bindgen/src/winmd/verify.rs b/crates/libs/bindgen/src/winmd/verify.rs index 6b36213fc3..c376d9d19d 100644 --- a/crates/libs/bindgen/src/winmd/verify.rs +++ b/crates/libs/bindgen/src/winmd/verify.rs @@ -36,7 +36,7 @@ pub fn verify(reader: &metadata::Reader) -> crate::Result<()> { fn not_type_ref(ty: &metadata::Type) -> crate::Result<()> { if let metadata::Type::TypeRef(ty) = ty { - return Err(crate::Error::new(&format!("missing type definition `{}`", ty.type_name()))); + return Err(crate::Error::new(&format!("missing type definition `{}`", ty))); } Ok(()) } diff --git a/crates/libs/bindgen/src/winmd/writer/mod.rs b/crates/libs/bindgen/src/winmd/writer/mod.rs index bd5f12f5bb..7ac4a08d61 100644 --- a/crates/libs/bindgen/src/winmd/writer/mod.rs +++ b/crates/libs/bindgen/src/winmd/writer/mod.rs @@ -234,7 +234,7 @@ impl Writer { usize_blob(1, blob); // count usize_blob(*bounds, blob); } - Type::TypeName => { + Type::Type => { let code = self.insert_type_ref("System", "Type"); blob.push(metadata::ELEMENT_TYPE_CLASS); usize_blob(code as usize, blob); diff --git a/crates/libs/bindgen/src/winmd/writer/type.rs b/crates/libs/bindgen/src/winmd/writer/type.rs index 3f0178654a..c0668c8ab9 100644 --- a/crates/libs/bindgen/src/winmd/writer/type.rs +++ b/crates/libs/bindgen/src/winmd/writer/type.rs @@ -34,7 +34,7 @@ pub enum Type { PCSTR, PCWSTR, BSTR, - TypeName, + Type, TypeRef(TypeName), GenericParam(u16), MutPtr(Box, usize), diff --git a/crates/libs/metadata/src/blob.rs b/crates/libs/metadata/src/blob.rs index 7d37bfefeb..398d5fb3b3 100644 --- a/crates/libs/metadata/src/blob.rs +++ b/crates/libs/metadata/src/blob.rs @@ -58,7 +58,7 @@ impl Blob { mods } - pub fn read_str(&mut self) -> &str { + pub fn read_str(&mut self) -> &'static str { let len = self.read_usize(); let value = unsafe { std::str::from_utf8_unchecked(&self.slice[..len]) }; self.offset(len); diff --git a/crates/libs/metadata/src/filter.rs b/crates/libs/metadata/src/filter.rs index 057586a6c9..f9efcfe7e1 100644 --- a/crates/libs/metadata/src/filter.rs +++ b/crates/libs/metadata/src/filter.rs @@ -83,8 +83,8 @@ mod tests { use super::*; fn includes_type_name(filter: &Filter, full_name: &'static str) -> bool { - let type_name = crate::parse_type_name(full_name); - filter.includes_type_name(type_name.0, type_name.1) + let type_name = crate::TypeName::parse(full_name); + filter.includes_type_name(type_name.namespace, type_name.name) } #[test] diff --git a/crates/libs/metadata/src/lib.rs b/crates/libs/metadata/src/lib.rs index 4606ca7ff4..2484783510 100644 --- a/crates/libs/metadata/src/lib.rs +++ b/crates/libs/metadata/src/lib.rs @@ -19,7 +19,7 @@ pub use attributes::*; pub use bindings::*; pub use blob::*; pub use codes::*; -pub use column::*; +use column::*; pub use file::*; use filter::*; pub use r#type::*; @@ -95,8 +95,7 @@ pub enum Value { F32(f32), F64(f64), String(String), - TypeName(String), - TypeRef(TypeDefOrRef), // TODO: needed? + TypeName(TypeName), EnumDef(TypeDef, Box), } diff --git a/crates/libs/metadata/src/reader.rs b/crates/libs/metadata/src/reader.rs index 51b4056d98..d60c98ba95 100644 --- a/crates/libs/metadata/src/reader.rs +++ b/crates/libs/metadata/src/reader.rs @@ -16,6 +16,8 @@ pub struct Reader { // TODO: riddle should just avoid nested structs nested: HashMap>, + // The reader needs to store the filter since standalone code generation needs more than just the filtered items + // in order to chase dependencies automatically. This is why `Reader::filter` can't just filter everything up front. filter: Filter, } @@ -170,11 +172,10 @@ impl Reader { if let Some(def) = self.get_type_def(full_name.namespace, full_name.name).next() { Type::TypeDef(def, Vec::new()) } else { - Type::TypeRef(code) + Type::TypeRef(full_name) } } - // TODO: this shouldn't be public pub fn type_from_blob(&self, blob: &mut Blob, enclosing: Option, generics: &[Type]) -> Type { // Used by WinRT to indicate that a struct input parameter is passed by reference rather than by value on the ABI. let is_const = blob.read_modifiers().iter().any(|def| def.type_name() == TypeName::IsConst); @@ -251,4 +252,4 @@ impl Reader { pub const REMAP_TYPES: [(TypeName, TypeName); 2] = [(TypeName::D2D_MATRIX_3X2_F, TypeName::Matrix3x2), (TypeName::D3DMATRIX, TypeName::Matrix4x4)]; // TODO: get rid of at least the second tuple if not the whole thing. -pub 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::TypeName), (TypeName::CHAR, Type::U8)]; +pub 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)]; diff --git a/crates/libs/metadata/src/tables.rs b/crates/libs/metadata/src/tables.rs index dcebe18664..4efce73d81 100644 --- a/crates/libs/metadata/src/tables.rs +++ b/crates/libs/metadata/src/tables.rs @@ -48,20 +48,18 @@ impl Attribute { } pub fn name(&self) -> &'static str { - let AttributeType::MemberRef(member) = self.ty(); - assert_eq!(member.name(), ".ctor"); - let MemberRefParent::TypeRef(ty) = member.parent(); + let AttributeType::MemberRef(ctor) = self.ty(); + let MemberRefParent::TypeRef(ty) = ctor.parent(); ty.name() } pub fn type_name(&self) -> TypeName { - let AttributeType::MemberRef(member) = self.ty(); - assert_eq!(member.name(), ".ctor"); - let MemberRefParent::TypeRef(ty) = member.parent(); + let AttributeType::MemberRef(ctor) = self.ty(); + let MemberRefParent::TypeRef(ty) = ctor.parent(); ty.type_name() } - pub fn args(&self) -> Vec<(String, Value)> { + pub fn args(&self) -> Vec<(&'static str, Value)> { let AttributeType::MemberRef(member) = self.ty(); let mut sig = member.blob(2); let mut values = self.blob(2); @@ -69,7 +67,7 @@ impl Attribute { let _this_and_gen_param_count = sig.read_usize(); let fixed_arg_count = sig.read_usize(); let _ret_type = sig.read_usize(); - let mut args: Vec<(String, Value)> = Vec::with_capacity(fixed_arg_count); + let mut args = Vec::with_capacity(fixed_arg_count); let reader = self.reader(); for _ in 0..fixed_arg_count { @@ -84,12 +82,12 @@ impl Attribute { Type::I64 => Value::I64(values.read_i64()), Type::U64 => Value::U64(values.read_u64()), Type::String => Value::String(values.read_str().to_string()), - Type::TypeName => Value::TypeName(values.read_str().to_string()), + Type::Type => Value::TypeName(TypeName::parse(values.read_str())), Type::TypeDef(def, _) => Value::EnumDef(def, Box::new(values.read_integer(def.underlying_type()))), rest => unimplemented!("{rest:?}"), }; - args.push((String::new(), arg)); + args.push(("", arg)); } let named_arg_count = values.read_u16(); @@ -98,28 +96,27 @@ impl Attribute { for _ in 0..named_arg_count { let _id = values.read_u8(); let arg_type = values.read_u8(); - let mut name = values.read_str().to_string(); + let mut name = values.read_str(); let arg = match arg_type { ELEMENT_TYPE_BOOLEAN => Value::Bool(values.read_bool()), ELEMENT_TYPE_I2 => Value::I16(values.read_i16()), ELEMENT_TYPE_I4 => Value::I32(values.read_i32()), ELEMENT_TYPE_U4 => Value::U32(values.read_u32()), ELEMENT_TYPE_STRING => Value::String(values.read_str().to_string()), - 0x50 => Value::TypeName(values.read_str().to_string()), + 0x50 => Value::TypeName(TypeName::parse(values.read_str())), 0x55 => { - let type_name = parse_type_name(&name); - let def = reader.get_type_def(type_name.0, type_name.1).next().expect("Type not found"); - name = values.read_str().to_string(); + let type_name = TypeName::parse(name); + let def = reader.get_type_def(type_name.namespace, type_name.name).next().expect("Type not found"); + name = values.read_str(); Value::EnumDef(def, Box::new(values.read_integer(def.underlying_type()))) } rest => unimplemented!("{rest:?}"), }; - args.push((name.to_string(), arg)); + args.push((name, arg)); } - // TODO: can we debug assert these? - assert_eq!(sig.slice.len(), 0); - assert_eq!(values.slice.len(), 0); + debug_assert_eq!(sig.slice.len(), 0); + debug_assert_eq!(values.slice.len(), 0); args } diff --git a/crates/libs/metadata/src/type.rs b/crates/libs/metadata/src/type.rs index d0f60e4de2..5c2c24eb61 100644 --- a/crates/libs/metadata/src/type.rs +++ b/crates/libs/metadata/src/type.rs @@ -23,12 +23,10 @@ pub enum Type { GUID, // Both Win32 and WinRT agree that this is represented by System.Guid String, // TODO: Win32 should use System.String when referring to an HSTRING IInspectable, // TODO: Win32 should use System.Object when referring to an IInspectable - - // Meta-type indicating type name in attribute blob. - TypeName, + Type, // System.Type is needed since WinRT attribute use this as a parameter type. // Regular ECMA-335 types that map to metadata - TypeRef(TypeDefOrRef), // Note: this ought to be a TypeName but that would require Type to have a lifetime reference. + TypeRef(TypeName), GenericParam(GenericParam), TypeDef(TypeDef, Vec), diff --git a/crates/libs/metadata/src/type_name.rs b/crates/libs/metadata/src/type_name.rs index ec599d5920..2740b153d4 100644 --- a/crates/libs/metadata/src/type_name.rs +++ b/crates/libs/metadata/src/type_name.rs @@ -2,7 +2,7 @@ use super::*; -#[derive(Copy, Clone, PartialEq, Eq)] +#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, Ord, PartialOrd)] pub struct TypeName { pub namespace: &'static str, pub name: &'static str, @@ -56,6 +56,11 @@ impl TypeName { pub fn new(namespace: &'static str, name: &'static str) -> Self { Self { namespace, name: trim_tick(name) } } + + pub fn parse(full_name: &'static str) -> Self { + let index = full_name.rfind('.').expect("Expected full name separated with `.`"); + Self::new(&full_name[0..index], &full_name[index + 1..]) + } } impl std::fmt::Display for TypeName { @@ -63,8 +68,3 @@ impl std::fmt::Display for TypeName { write!(fmt, "{}.{}", self.namespace, self.name) } } - -pub fn parse_type_name(full_name: &str) -> (&str, &str) { - let index = full_name.rfind('.').expect("Expected full name separated with `.`"); - (&full_name[0..index], &full_name[index + 1..]) -} diff --git a/crates/tests/metadata/tests/attribute_enum.rs b/crates/tests/metadata/tests/attribute_enum.rs index 6944bbf45e..6692e3d028 100644 --- a/crates/tests/metadata/tests/attribute_enum.rs +++ b/crates/tests/metadata/tests/attribute_enum.rs @@ -37,7 +37,7 @@ fn check_attr_arg_enum(attr: Attribute, arg_name: &str, expected_type: &str, exp let (_, value) = attr .args() .drain(..) - .find(|(name, _)| name == arg_name) + .find(|(name, _)| *name == arg_name) .unwrap(); if let Value::EnumDef(ty, value) = value {