Skip to content

Commit

Permalink
Type name deferral in windows-metadata and windows-bindgen (#3039)
Browse files Browse the repository at this point in the history
  • Loading branch information
kennykerr authored May 14, 2024
1 parent 1afefbe commit a036ce6
Show file tree
Hide file tree
Showing 16 changed files with 117 additions and 164 deletions.
2 changes: 0 additions & 2 deletions crates/libs/bindgen/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,8 +111,6 @@ where
let input = read_input(&input)?;
let reader = metadata::Reader::filter(input, &include, &exclude, &config);

winmd::verify(reader)?;

match extension(&output) {
"rdl" => rdl::from_reader(reader, config, &output)?,
"winmd" => winmd::from_reader(reader, config, &output)?,
Expand Down
36 changes: 18 additions & 18 deletions crates/libs/bindgen/src/metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ impl Signature {
match &self.return_type {
Type::Void if self.is_retval() => SignatureKind::ReturnValue,
Type::Void => SignatureKind::ReturnVoid,
Type::HRESULT => {
Type::Name(TypeName::HResult) => {
if self.params.len() >= 2 {
if let Some((guid, object)) = signature_param_is_query(&self.params) {
if self.params[object].def.flags().contains(ParamAttributes::Optional) {
Expand Down Expand Up @@ -357,7 +357,7 @@ fn param_or_enum(row: Param) -> Option<String> {
}

fn signature_param_is_query(params: &[SignatureParam]) -> Option<(usize, usize)> {
if let Some(guid) = params.iter().rposition(|param| param.ty == Type::ConstPtr(Box::new(Type::GUID), 1) && !param.def.flags().contains(ParamAttributes::Out)) {
if let Some(guid) = params.iter().rposition(|param| param.ty == Type::ConstPtr(Box::new(Type::Name(TypeName::GUID)), 1) && !param.def.flags().contains(ParamAttributes::Out)) {
if let Some(object) = params.iter().rposition(|param| param.ty == Type::MutPtr(Box::new(Type::Void), 2) && param.def.has_attribute("ComOutPtrAttribute")) {
return Some((guid, object));
}
Expand All @@ -377,7 +377,7 @@ fn method_def_last_error(row: MethodDef) -> bool {
pub fn type_is_borrowed(ty: &Type) -> bool {
match ty {
Type::TypeDef(row, _) => !type_def_is_blittable(*row),
Type::BSTR | Type::VARIANT | Type::PROPVARIANT | Type::PCSTR | Type::PCWSTR | Type::IInspectable | Type::IUnknown | Type::GenericParam(_) => true,
Type::Name(TypeName::BSTR) | Type::Name(TypeName::VARIANT) | Type::Name(TypeName::PROPVARIANT) | Type::Const(TypeName::PSTR) | Type::Const(TypeName::PWSTR) | Type::Object | Type::Name(TypeName::IUnknown) | Type::GenericParam(_) => true,
_ => false,
}
}
Expand Down Expand Up @@ -506,7 +506,7 @@ pub fn field_is_copyable(row: Field, enclosing: TypeDef) -> bool {
pub fn type_is_blittable(ty: &Type) -> bool {
match ty {
Type::TypeDef(row, _) => type_def_is_blittable(*row),
Type::String | Type::BSTR | Type::VARIANT | Type::PROPVARIANT | Type::IInspectable | Type::IUnknown | Type::GenericParam(_) => false,
Type::String | Type::Name(TypeName::BSTR) | Type::Name(TypeName::VARIANT) | Type::Name(TypeName::PROPVARIANT) | Type::Object | Type::Name(TypeName::IUnknown) | Type::GenericParam(_) => false,
Type::Win32Array(kind, _) => type_is_blittable(kind),
Type::WinrtArray(kind) => type_is_blittable(kind),
_ => true,
Expand All @@ -516,7 +516,7 @@ pub fn type_is_blittable(ty: &Type) -> bool {
fn type_is_copyable(ty: &Type) -> bool {
match ty {
Type::TypeDef(row, _) => type_def_is_copyable(*row),
Type::String | Type::BSTR | Type::VARIANT | Type::PROPVARIANT | Type::IInspectable | Type::IUnknown | Type::GenericParam(_) => false,
Type::String | Type::Name(TypeName::BSTR) | Type::Name(TypeName::VARIANT) | Type::Name(TypeName::PROPVARIANT) | Type::Object | Type::Name(TypeName::IUnknown) | Type::GenericParam(_) => false,
Type::Win32Array(kind, _) => type_is_copyable(kind),
Type::WinrtArray(kind) => type_is_copyable(kind),
_ => true,
Expand Down Expand Up @@ -557,7 +557,7 @@ pub fn type_is_struct(ty: &Type) -> bool {
// nested structs. Fortunately, this is rare enough that this check is sufficient.
match ty {
Type::TypeDef(row, _) => row.kind() == TypeKind::Struct && !type_def_is_handle(*row),
Type::GUID => true,
Type::Name(TypeName::GUID) => true,
_ => false,
}
}
Expand All @@ -574,7 +574,7 @@ fn type_def_is_primitive(row: TypeDef) -> bool {
pub fn type_is_primitive(ty: &Type) -> bool {
match ty {
Type::TypeDef(row, _) => type_def_is_primitive(*row),
Type::Bool | Type::Char | Type::I8 | Type::U8 | Type::I16 | Type::U16 | Type::I32 | Type::U32 | Type::I64 | Type::U64 | Type::F32 | Type::F64 | Type::ISize | Type::USize | Type::HRESULT | Type::ConstPtr(_, _) | Type::MutPtr(_, _) => true,
Type::Bool | Type::Char | Type::I8 | Type::U8 | Type::I16 | Type::U16 | Type::I32 | Type::U32 | Type::I64 | Type::U64 | Type::F32 | Type::F64 | Type::ISize | Type::USize | Type::Name(TypeName::HResult) | Type::ConstPtr(_, _) | Type::MutPtr(_, _) => true,
_ => false,
}
}
Expand Down Expand Up @@ -675,9 +675,9 @@ fn type_signature(ty: &Type) -> String {
Type::ISize => "is".to_string(),
Type::USize => "us".to_string(),
Type::String => "string".to_string(),
Type::IInspectable => "cinterface(IInspectable)".to_string(),
Type::GUID => "g16".to_string(),
Type::HRESULT => "struct(Windows.Foundation.HResult;i4)".to_string(),
Type::Object => "cinterface(IInspectable)".to_string(),
Type::Name(TypeName::GUID) => "g16".to_string(),
Type::Name(TypeName::HResult) => "struct(Windows.Foundation.HResult;i4)".to_string(),
Type::TypeDef(row, generics) => type_def_signature(*row, generics),
rest => unimplemented!("{rest:?}"),
}
Expand Down Expand Up @@ -775,17 +775,17 @@ fn type_def_is_nullable(row: TypeDef) -> bool {
pub fn type_is_nullable(ty: &Type) -> bool {
match ty {
Type::TypeDef(row, _) => type_def_is_nullable(*row),
Type::IInspectable | Type::IUnknown => true,
Type::Object | Type::Name(TypeName::IUnknown) => true,
_ => false,
}
}

pub fn type_def_vtables(row: TypeDef) -> Vec<Type> {
let mut result = Vec::new();
if row.flags().contains(TypeAttributes::WindowsRuntime) {
result.push(Type::IUnknown);
result.push(Type::Name(TypeName::IUnknown));
if row.kind() != TypeKind::Delegate {
result.push(Type::IInspectable);
result.push(Type::Object);
}
} else {
let mut next = row;
Expand All @@ -795,13 +795,13 @@ pub fn type_def_vtables(row: TypeDef) -> Vec<Type> {
next = row;
result.insert(0, base);
}
Type::IInspectable => {
result.insert(0, Type::IUnknown);
result.insert(1, Type::IInspectable);
Type::Object => {
result.insert(0, Type::Name(TypeName::IUnknown));
result.insert(1, Type::Object);
break;
}
Type::IUnknown => {
result.insert(0, Type::IUnknown);
Type::Name(TypeName::IUnknown) => {
result.insert(0, Type::Name(TypeName::IUnknown));
break;
}
rest => unimplemented!("{rest:?}"),
Expand Down
22 changes: 10 additions & 12 deletions crates/libs/bindgen/src/rdl/from_reader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -339,11 +339,15 @@ impl Writer {

// TODO: dialect-specific keywords for "well-known types" that don't map to metadata in all cases.
metadata::Type::String => quote! { HSTRING },
metadata::Type::HRESULT => quote! { HRESULT },
metadata::Type::GUID => quote! { GUID },
metadata::Type::IInspectable => quote! { IInspectable },
metadata::Type::IUnknown => quote! { IUnknown },

metadata::Type::Name(metadata::TypeName::HResult) => quote! { HRESULT },
metadata::Type::Name(metadata::TypeName::GUID) => quote! { GUID },
metadata::Type::Object => quote! { IInspectable },
metadata::Type::Name(metadata::TypeName::IUnknown) => quote! { IUnknown },
metadata::Type::Name(metadata::TypeName::BSTR) => quote! { BSTR },
metadata::Type::Name(metadata::TypeName::PSTR) => quote! { PSTR },
metadata::Type::Name(metadata::TypeName::PWSTR) => quote! { PWSTR },
metadata::Type::Const(metadata::TypeName::PSTR) => quote! { PCSTR },
metadata::Type::Const(metadata::TypeName::PWSTR) => quote! { PCWSTR },
metadata::Type::TypeDef(def, generics) => {
let namespace = self.namespace(def.namespace());
let name = to_ident(def.name());
Expand All @@ -355,7 +359,7 @@ impl Writer {
}
}

metadata::Type::TypeRef(type_name) => {
metadata::Type::Name(type_name) => {
let namespace = self.namespace(type_name.namespace());
let name = to_ident(type_name.name());
quote! { #namespace #name }
Expand All @@ -368,12 +372,6 @@ impl Writer {
metadata::Type::MutPtr(ty, _pointers) => self.ty(ty),
metadata::Type::ConstPtr(ty, _pointers) => self.ty(ty),
metadata::Type::Win32Array(ty, _len) => self.ty(ty),
// TODO: these types should just be regular metadata type defs
metadata::Type::PSTR => quote! { PSTR },
metadata::Type::PWSTR => quote! { PWSTR },
metadata::Type::PCSTR => quote! { PCSTR },
metadata::Type::PCWSTR => quote! { PCWSTR },
metadata::Type::BSTR => quote! { BSTR },
metadata::Type::PrimitiveOrEnum(_, ty) => self.ty(ty),
rest => unimplemented!("{rest:?}"),
}
Expand Down
12 changes: 6 additions & 6 deletions crates/libs/bindgen/src/rust/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ pub fn writer(writer: &Writer, def: metadata::Field) -> TokenStream {
}
} else if let Some(guid) = field_guid(def) {
let value = writer.guid(&guid);
let guid = writer.type_name(&metadata::Type::GUID);
let guid = writer.type_name(&metadata::Type::Name(metadata::TypeName::GUID));
quote! {
pub const #name: #guid = #value;
}
Expand All @@ -80,7 +80,7 @@ pub fn writer(writer: &Writer, def: metadata::Field) -> TokenStream {

fn is_signed_error(ty: &metadata::Type) -> bool {
match ty {
metadata::Type::HRESULT => true,
metadata::Type::Name(metadata::TypeName::HResult) => true,
metadata::Type::TypeDef(def, _) => def.type_name() == metadata::TypeName::NTSTATUS,
_ => false,
}
Expand Down Expand Up @@ -109,7 +109,7 @@ fn field_initializer<'a>(writer: &Writer, field: metadata::Field, input: &'a str
let name = to_ident(field.name());

match field.ty(None) {
metadata::Type::GUID => {
metadata::Type::Name(metadata::TypeName::GUID) => {
let (literals, rest) = read_literal_array(input, 11);
let value = writer.guid(&metadata::Guid::from_string_args(&literals));
(quote! { #name: #value, }, rest)
Expand Down Expand Up @@ -137,7 +137,7 @@ fn constant(def: metadata::Field) -> Option<String> {
def.find_attribute("ConstantAttribute").map(|attribute| {
let args = attribute.args();
match &args[0].1 {
metadata::Value::String(value) => value.clone(),
metadata::Value::String(value) => value.to_string(),
rest => unimplemented!("{rest:?}"),
}
})
Expand Down Expand Up @@ -200,7 +200,7 @@ fn field_is_ansi(row: metadata::Field) -> bool {

fn type_has_replacement(ty: &metadata::Type) -> bool {
match ty {
metadata::Type::HRESULT | metadata::Type::PCSTR | metadata::Type::PCWSTR => true,
metadata::Type::Name(metadata::TypeName::HResult) | metadata::Type::Const(metadata::TypeName::PSTR) | metadata::Type::Const(metadata::TypeName::PWSTR) => true,
metadata::Type::TypeDef(row, _) => metadata::type_def_is_handle(*row) || row.kind() == metadata::TypeKind::Enum,
_ => false,
}
Expand All @@ -209,7 +209,7 @@ fn type_has_replacement(ty: &metadata::Type) -> bool {
fn type_underlying_type(ty: &metadata::Type) -> metadata::Type {
match ty {
metadata::Type::TypeDef(row, _) => row.underlying_type(),
metadata::Type::HRESULT => metadata::Type::I32,
metadata::Type::Name(metadata::TypeName::HResult) => metadata::Type::I32,
_ => ty.clone(),
}
}
6 changes: 3 additions & 3 deletions crates/libs/bindgen/src/rust/implements.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ pub fn writer(writer: &Writer, def: metadata::TypeDef) -> TokenStream {
let mut requires = quote! {};
let type_ident = quote! { #type_ident<#generic_names> };
let vtables = metadata::type_def_vtables(def);
let has_unknown_base = matches!(vtables.first(), Some(metadata::Type::IUnknown));
let has_unknown_base = matches!(vtables.first(), Some(metadata::Type::Name(metadata::TypeName::IUnknown)));

fn gen_required_trait(writer: &Writer, def: metadata::TypeDef, generics: &[metadata::Type]) -> TokenStream {
let name = writer.type_def_name_imp(def, generics, "_Impl");
Expand Down Expand Up @@ -104,8 +104,8 @@ pub fn writer(writer: &Writer, def: metadata::TypeDef) -> TokenStream {
let mut methods = quote! {};

match vtables.last() {
Some(metadata::Type::IUnknown) => methods.combine(&quote! { base__: windows_core::IUnknown_Vtbl::new::<Identity, OFFSET>(), }),
Some(metadata::Type::IInspectable) => methods.combine(&quote! { base__: windows_core::IInspectable_Vtbl::new::<Identity, #type_ident, OFFSET>(), }),
Some(metadata::Type::Name(metadata::TypeName::IUnknown)) => methods.combine(&quote! { base__: windows_core::IUnknown_Vtbl::new::<Identity, OFFSET>(), }),
Some(metadata::Type::Object) => methods.combine(&quote! { base__: windows_core::IInspectable_Vtbl::new::<Identity, #type_ident, OFFSET>(), }),
Some(metadata::Type::TypeDef(def, generics)) => {
let name = writer.type_def_name_imp(*def, generics, "_Vtbl");
if has_unknown_base {
Expand Down
4 changes: 2 additions & 2 deletions crates/libs/bindgen/src/rust/interfaces.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ fn gen_sys_interface(writer: &Writer, def: metadata::TypeDef) -> TokenStream {
}

let vtables = metadata::type_def_vtables(def);
let has_unknown_base = matches!(vtables.first(), Some(metadata::Type::IUnknown));
let has_unknown_base = matches!(vtables.first(), Some(metadata::Type::Name(metadata::TypeName::IUnknown)));

let mut tokens = quote! {};

Expand Down Expand Up @@ -42,7 +42,7 @@ fn gen_win_interface(writer: &Writer, def: metadata::TypeDef) -> TokenStream {
let features = writer.cfg_features(&cfg);
let interfaces = metadata::type_interfaces(&metadata::Type::TypeDef(def, generics.to_vec()));
let vtables = metadata::type_def_vtables(def);
let has_unknown_base = matches!(vtables.first(), Some(metadata::Type::IUnknown));
let has_unknown_base = matches!(vtables.first(), Some(metadata::Type::Name(metadata::TypeName::IUnknown)));

let mut tokens = quote! {};

Expand Down
2 changes: 1 addition & 1 deletion crates/libs/bindgen/src/rust/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ fn namespace(writer: &Writer, tree: &Tree) -> String {
fn namespace_impl(writer: &Writer, tree: &Tree) -> String {
let writer = &mut writer.clone();
writer.namespace = tree.namespace;
let mut types = std::collections::BTreeMap::<&str, TokenStream>::new();
let mut types = std::collections::BTreeMap::new();

for item in writer.reader.namespace_items(tree.namespace) {
if let metadata::Item::Type(def) = item {
Expand Down
30 changes: 15 additions & 15 deletions crates/libs/bindgen/src/rust/standalone.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ pub fn standalone_imp(writer: &Writer) -> String {

for ty in types {
match ty {
metadata::Type::HRESULT if writer.sys => sorted.insert("HRESULT", quote! { pub type HRESULT = i32; }),
metadata::Type::IUnknown if writer.sys => sorted.insert(
metadata::Type::Name(metadata::TypeName::HResult) if writer.sys => sorted.insert("HRESULT", quote! { pub type HRESULT = i32; }),
metadata::Type::Name(metadata::TypeName::IUnknown) if writer.sys => sorted.insert(
"IUnknown",
if !writer.vtbl {
quote! {}
Expand All @@ -37,7 +37,7 @@ pub fn standalone_imp(writer: &Writer) -> String {
}
},
),
metadata::Type::IInspectable if writer.sys => sorted.insert(
metadata::Type::Object if writer.sys => sorted.insert(
"IInspectable",
if !writer.vtbl {
quote! {}
Expand All @@ -54,12 +54,12 @@ pub fn standalone_imp(writer: &Writer) -> String {
}
},
),
metadata::Type::PSTR if writer.sys => sorted.insert("PSTR", quote! { pub type PSTR = *mut u8; }),
metadata::Type::PWSTR if writer.sys => sorted.insert("PWSTR", quote! { pub type PWSTR = *mut u16; }),
metadata::Type::PCSTR if writer.sys => sorted.insert("PCSTR", quote! { pub type PCSTR = *const u8; }),
metadata::Type::PCWSTR if writer.sys => sorted.insert("PCWSTR", quote! { pub type PCWSTR = *const u16; }),
metadata::Type::BSTR if writer.sys => sorted.insert("BSTR", quote! { pub type BSTR = *const u16; }),
metadata::Type::GUID if writer.sys => {
metadata::Type::Name(metadata::TypeName::PSTR) if writer.sys => sorted.insert("PSTR", quote! { pub type PSTR = *mut u8; }),
metadata::Type::Name(metadata::TypeName::PWSTR) if writer.sys => sorted.insert("PWSTR", quote! { pub type PWSTR = *mut u16; }),
metadata::Type::Const(metadata::TypeName::PSTR) if writer.sys => sorted.insert("PCSTR", quote! { pub type PCSTR = *const u8; }),
metadata::Type::Const(metadata::TypeName::PWSTR) if writer.sys => sorted.insert("PCWSTR", quote! { pub type PCWSTR = *const u16; }),
metadata::Type::Name(metadata::TypeName::BSTR) if writer.sys => sorted.insert("BSTR", quote! { pub type BSTR = *const u16; }),
metadata::Type::Name(metadata::TypeName::GUID) if writer.sys => {
sorted.insert(
"GUID",
quote! {
Expand Down Expand Up @@ -128,11 +128,11 @@ fn type_collect_standalone(writer: &Writer, ty: &metadata::Type, set: &mut std::

if writer.vtbl {
match ty {
metadata::Type::IUnknown => {
set.insert(metadata::Type::GUID);
set.insert(metadata::Type::HRESULT);
metadata::Type::Name(metadata::TypeName::IUnknown) => {
set.insert(metadata::Type::Name(metadata::TypeName::GUID));
set.insert(metadata::Type::Name(metadata::TypeName::HResult));
}
metadata::Type::IInspectable => type_collect_standalone(writer, &metadata::Type::IUnknown, set),
metadata::Type::Object => type_collect_standalone(writer, &metadata::Type::Name(metadata::TypeName::IUnknown), set),
_ => {}
}
}
Expand Down Expand Up @@ -188,12 +188,12 @@ fn type_collect_standalone(writer: &Writer, ty: &metadata::Type, set: &mut std::
match def.kind() {
metadata::TypeKind::Struct => {
if def.fields().next().is_none() && metadata::type_def_guid(def).is_some() {
set.insert(metadata::Type::GUID);
set.insert(metadata::Type::Name(metadata::TypeName::GUID));
}
}
metadata::TypeKind::Interface => {
if def.flags().contains(metadata::TypeAttributes::WindowsRuntime) {
type_collect_standalone(writer, &metadata::Type::IInspectable, set);
type_collect_standalone(writer, &metadata::Type::Object, set);
}
}
_ => {}
Expand Down
2 changes: 1 addition & 1 deletion crates/libs/bindgen/src/rust/structs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ pub fn writer(writer: &Writer, def: metadata::TypeDef) -> TokenStream {
if let Some(guid) = clsid(def) {
let ident = to_ident(def.name());
let value = writer.guid(&guid);
let guid = writer.type_name(&metadata::Type::GUID);
let guid = writer.type_name(&metadata::Type::Name(metadata::TypeName::GUID));
return quote! {
pub const #ident: #guid = #value;
};
Expand Down
Loading

0 comments on commit a036ce6

Please sign in to comment.