Skip to content

Commit

Permalink
Add "vtbl" option for low-level interface vtable generation (#2845)
Browse files Browse the repository at this point in the history
  • Loading branch information
kennykerr authored Feb 14, 2024
1 parent ece2390 commit a86c71a
Show file tree
Hide file tree
Showing 549 changed files with 1,400 additions and 12,858 deletions.
2 changes: 1 addition & 1 deletion crates/libs/bindgen/src/rust/delegates.rs
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ fn gen_win_delegate(writer: &Writer, def: metadata::TypeDef) -> TokenStream {

tokens.combine(&writer.interface_trait(def, generics, &ident, &constraints, &features, true));
tokens.combine(&writer.interface_winrt_trait(def, generics, &ident, &constraints, &phantoms, &features));
tokens.combine(&writer.interface_vtbl(def, generics, &ident, &constraints, &features));
tokens.combine(&writer.interface_vtbl(def, generics, &constraints, &features));
tokens
}

Expand Down
27 changes: 25 additions & 2 deletions crates/libs/bindgen/src/rust/interfaces.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,35 @@ use super::*;

pub fn writer(writer: &Writer, def: metadata::TypeDef) -> TokenStream {
if writer.sys {
quote! {}
gen_sys_interface(writer, def)
} else {
gen_win_interface(writer, def)
}
}

fn gen_sys_interface(writer: &Writer, def: metadata::TypeDef) -> TokenStream {
if !writer.vtbl {
return quote! {};
}

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

let mut tokens = quote! {};

if has_unknown_base {
let iid_ident: TokenStream = format!("IID_{}", def.name()).into();
let iid = writer.guid_literal(metadata::type_def_guid(def));

tokens.combine(&quote! {
pub const #iid_ident: GUID = GUID::from_u128(#iid);
});
}

tokens.combine(&writer.interface_vtbl(def, &[], &TokenStream::new(), &TokenStream::new()));
tokens
}

fn gen_win_interface(writer: &Writer, def: metadata::TypeDef) -> TokenStream {
let generics = &metadata::type_def_generics(def);
let ident = writer.type_def_name(def, generics);
Expand Down Expand Up @@ -150,6 +173,6 @@ fn gen_win_interface(writer: &Writer, def: metadata::TypeDef) -> TokenStream {
}

tokens.combine(&writer.interface_trait(def, generics, &ident, &constraints, &features, has_unknown_base));
tokens.combine(&writer.interface_vtbl(def, generics, &ident, &constraints, &features));
tokens.combine(&writer.interface_vtbl(def, generics, &constraints, &features));
tokens
}
1 change: 1 addition & 0 deletions crates/libs/bindgen/src/rust/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ pub fn from_reader(reader: &'static metadata::Reader, mut config: std::collectio
writer.implement = config.remove("implement").is_some();
writer.minimal = config.remove("minimal").is_some();
writer.no_inner_attributes = config.remove("no-inner-attributes").is_some();
writer.vtbl = config.remove("vtbl").is_some();

if writer.package && writer.flatten {
return Err(Error::new("cannot combine `package` and `flatten` configuration values"));
Expand Down
99 changes: 77 additions & 22 deletions crates/libs/bindgen/src/rust/standalone.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ pub fn standalone_imp(writer: &Writer) -> String {
let mut constants = std::collections::BTreeSet::new();

for item in writer.reader.items() {
item_collect_standalone(item.clone(), &mut types);
item_collect_standalone(writer, item.clone(), &mut types);

match item {
metadata::Item::Type(_) => {}
Expand All @@ -21,9 +21,39 @@ 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::String if writer.sys => sorted.insert("HSTRING", quote! { pub type HSTRING = *mut ::core::ffi::c_void; }),
metadata::Type::IUnknown if writer.sys => sorted.insert("IUnknown", quote! { pub type IUnknown = *mut ::core::ffi::c_void; }),
metadata::Type::IInspectable if writer.sys => sorted.insert("IInspectable", quote! { pub type IInspectable = *mut ::core::ffi::c_void; }),
metadata::Type::IUnknown if writer.sys => sorted.insert(
"IUnknown",
if !writer.vtbl {
quote! {}
} else {
quote! {
pub const IID_IUnknown: GUID = GUID::from_u128(0x00000000_0000_0000_c000_000000000046);
#[repr(C)]
pub struct IUnknown_Vtbl {
pub QueryInterface: unsafe extern "system" fn(this: *mut ::core::ffi::c_void, iid: *const GUID, interface: *mut *mut ::core::ffi::c_void) -> HRESULT,
pub AddRef: unsafe extern "system" fn(this: *mut ::core::ffi::c_void) -> u32,
pub Release: unsafe extern "system" fn(this: *mut ::core::ffi::c_void) -> u32,
}
}
},
),
metadata::Type::IInspectable if writer.sys => sorted.insert(
"IInspectable",
if !writer.vtbl {
quote! {}
} else {
quote! {
pub const IID_IInspectable: GUID = GUID::from_u128(0xaf86e2e0_b12d_4c6a_9c5a_d7aa65101e90);
#[repr(C)]
pub struct IInspectable_Vtbl {
pub base: IUnknown_Vtbl,
pub GetIids: unsafe extern "system" fn(this: *mut std::ffi::c_void, count: *mut u32, values: *mut *mut GUID) -> HRESULT,
pub GetRuntimeClassName: unsafe extern "system" fn(this: *mut std::ffi::c_void, value: *mut *mut std::ffi::c_void) -> HRESULT,
pub GetTrustLevel: unsafe extern "system" fn(this: *mut std::ffi::c_void, value: *mut i32) -> HRESULT,
}
}
},
),
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; }),
Expand Down Expand Up @@ -115,24 +145,35 @@ impl SortedTokens {
}
}

fn item_collect_standalone(item: metadata::Item, set: &mut std::collections::BTreeSet<metadata::Type>) {
fn item_collect_standalone(writer: &Writer, item: metadata::Item, set: &mut std::collections::BTreeSet<metadata::Type>) {
match item {
metadata::Item::Type(def) => type_collect_standalone(&metadata::Type::TypeDef(def, vec![]), set),
metadata::Item::Const(def) => type_collect_standalone(&def.ty(None).to_const_type(), set),
metadata::Item::Type(def) => type_collect_standalone(writer, &metadata::Type::TypeDef(def, vec![]), set),
metadata::Item::Const(def) => type_collect_standalone(writer, &def.ty(None).to_const_type(), set),
metadata::Item::Fn(def, namespace) => {
let signature = metadata::method_def_signature(namespace, def, &[]);
type_collect_standalone(&signature.return_type, set);
signature.params.iter().for_each(|param| type_collect_standalone(&param.ty, set));
type_collect_standalone(writer, &signature.return_type, set);
signature.params.iter().for_each(|param| type_collect_standalone(writer, &param.ty, set));
}
}
}
// TODO: remove or move to riddle
fn type_collect_standalone(ty: &metadata::Type, set: &mut std::collections::BTreeSet<metadata::Type>) {
fn type_collect_standalone(writer: &Writer, ty: &metadata::Type, set: &mut std::collections::BTreeSet<metadata::Type>) {
let ty = ty.to_underlying_type();
if !set.insert(ty.clone()) {
return;
}

if writer.vtbl {
match ty {
metadata::Type::IUnknown => {
set.insert(metadata::Type::GUID);
set.insert(metadata::Type::HRESULT);
}
metadata::Type::IInspectable => type_collect_standalone(writer, &metadata::Type::IUnknown, set),
_ => {}
}
}

let metadata::Type::TypeDef(def, generics) = ty.to_underlying_type() else {
return;
};
Expand All @@ -148,45 +189,59 @@ fn type_collect_standalone(ty: &metadata::Type, set: &mut std::collections::BTre
if !type_name.namespace.is_empty() {
for row in def.reader().get_type_def(type_name.namespace, type_name.name) {
if def != row {
type_collect_standalone(&metadata::Type::TypeDef(row, Vec::new()), set);
type_collect_standalone(writer, &metadata::Type::TypeDef(row, Vec::new()), set);
}
}
}

for generic in &generics {
type_collect_standalone(generic, set);
type_collect_standalone(writer, generic, set);
}

for field in def.fields() {
let ty = field.ty(Some(def));
if let metadata::Type::TypeDef(def, _) = &ty {
if def.namespace().is_empty() {
continue;
}
}
type_collect_standalone(&ty, set);
type_collect_standalone(writer, &ty, set);
}

for method in def.methods() {
// Skip delegate pseudo-constructors.
if method.name() == ".ctor" {
continue;
}
let signature = metadata::method_def_signature(def.namespace(), method, &generics);
type_collect_standalone(&signature.return_type, set);
signature.params.iter().for_each(|param| type_collect_standalone(&param.ty, set));
type_collect_standalone(writer, &signature.return_type, set);
signature.params.iter().for_each(|param| type_collect_standalone(writer, &param.ty, set));
}

for interface in metadata::type_interfaces(&ty) {
type_collect_standalone(&interface.ty, set);
type_collect_standalone(writer, &interface.ty, set);
}
if def.kind() == metadata::TypeKind::Struct && def.fields().next().is_none() && metadata::type_def_guid(def).is_some() {
set.insert(metadata::Type::GUID);

match def.kind() {
metadata::TypeKind::Struct => {
if def.fields().next().is_none() && metadata::type_def_guid(def).is_some() {
set.insert(metadata::Type::GUID);
}
}
metadata::TypeKind::Interface => {
if def.flags().contains(metadata::TypeAttributes::WindowsRuntime) {
type_collect_standalone(writer, &metadata::Type::IInspectable, set);
}
}
_ => {}
}

type_collect_standalone_nested(def, set);
type_collect_standalone_nested(writer, def, set);
}

fn type_collect_standalone_nested(td: metadata::TypeDef, set: &mut std::collections::BTreeSet<metadata::Type>) {
fn type_collect_standalone_nested(writer: &Writer, td: metadata::TypeDef, set: &mut std::collections::BTreeSet<metadata::Type>) {
for nested in td.reader().nested_types(td) {
type_collect_standalone_nested(nested, set);
type_collect_standalone_nested(writer, nested, set);

for field in nested.fields() {
let ty = field.ty(Some(nested));
Expand All @@ -197,7 +252,7 @@ fn type_collect_standalone_nested(td: metadata::TypeDef, set: &mut std::collecti
continue;
}
}
type_collect_standalone(&ty, set);
type_collect_standalone(writer, &ty, set);
}
}
}
35 changes: 25 additions & 10 deletions crates/libs/bindgen/src/rust/writer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ pub struct Writer {
pub package: bool, // default is single file with no cfg - implies !flatten
pub minimal: bool, // strips out enumerators - in future possibly other helpers as well
pub no_inner_attributes: bool, // skips the inner attributes at the start of the file
pub vtbl: bool, // include minimal vtbl layout support for interfaces
}

impl Writer {
Expand All @@ -34,6 +35,7 @@ impl Writer {
package: false,
minimal: false,
no_inner_attributes: false,
vtbl: false,
}
}

Expand Down Expand Up @@ -111,8 +113,12 @@ impl Writer {
metadata::Type::ISize => quote! { isize },
metadata::Type::USize => quote! { usize },
metadata::Type::String => {
let crate_name = self.crate_name();
quote! { #crate_name HSTRING }
if self.sys {
quote! { *mut ::core::ffi::c_void }
} else {
let crate_name = self.crate_name();
quote! { #crate_name HSTRING }
}
}
metadata::Type::BSTR => {
let crate_name = self.crate_name();
Expand All @@ -127,16 +133,24 @@ impl Writer {
quote! { #crate_name PROPVARIANT }
}
metadata::Type::IInspectable => {
let crate_name = self.crate_name();
quote! { #crate_name IInspectable }
if self.sys {
quote! { *mut ::core::ffi::c_void }
} else {
let crate_name = self.crate_name();
quote! { #crate_name IInspectable }
}
}
metadata::Type::GUID => {
let crate_name = self.crate_name();
quote! { #crate_name GUID }
}
metadata::Type::IUnknown => {
let crate_name = self.crate_name();
quote! { #crate_name IUnknown }
if self.sys {
quote! { *mut ::core::ffi::c_void }
} else {
let crate_name = self.crate_name();
quote! { #crate_name IUnknown }
}
}
metadata::Type::HRESULT => {
let crate_name = self.crate_name();
Expand Down Expand Up @@ -732,16 +746,17 @@ impl Writer {
}
}
}
pub fn interface_vtbl(&self, def: metadata::TypeDef, generics: &[metadata::Type], _ident: &TokenStream, constraints: &TokenStream, features: &TokenStream) -> TokenStream {
pub fn interface_vtbl(&self, def: metadata::TypeDef, generics: &[metadata::Type], constraints: &TokenStream, features: &TokenStream) -> TokenStream {
let vtbl = self.type_def_vtbl_name(def, generics);
let mut methods = quote! {};
let mut method_names = MethodNames::new();
method_names.add_vtable_types(def);
let phantoms = self.generic_named_phantoms(generics);
let crate_name = self.crate_name();

match metadata::type_def_vtables(def).last() {
Some(metadata::Type::IUnknown) => methods.combine(&quote! { pub base__: ::windows_core::IUnknown_Vtbl, }),
Some(metadata::Type::IInspectable) => methods.combine(&quote! { pub base__: ::windows_core::IInspectable_Vtbl, }),
Some(metadata::Type::IUnknown) => methods.combine(&quote! { pub base__: #crate_name IUnknown_Vtbl, }),
Some(metadata::Type::IInspectable) => methods.combine(&quote! { pub base__: #crate_name IInspectable_Vtbl, }),
Some(metadata::Type::TypeDef(def, _)) => {
let vtbl = self.type_def_vtbl_name(*def, &[]);
methods.combine(&quote! { pub base__: #vtbl, });
Expand Down Expand Up @@ -777,7 +792,7 @@ impl Writer {

quote! {
#features
#[repr(C)] #[doc(hidden)] pub struct #vtbl where #constraints {
#[repr(C)] pub struct #vtbl where #constraints {
#methods
#(pub #phantoms)*
}
Expand Down
14 changes: 6 additions & 8 deletions crates/libs/core/src/imp/bindings.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
// Bindings generated by `windows-bindgen` 0.52.0

#![allow(non_snake_case, non_upper_case_globals, non_camel_case_types, dead_code, clippy::all)]
::windows_targets::link!("api-ms-win-core-winrt-error-l1-1-0.dll" "system" fn RoOriginateError(error : HRESULT, message : HSTRING) -> BOOL);
::windows_targets::link!("api-ms-win-core-winrt-l1-1-0.dll" "system" fn RoGetActivationFactory(activatableclassid : HSTRING, iid : *const GUID, factory : *mut *mut ::core::ffi::c_void) -> HRESULT);
::windows_targets::link!("api-ms-win-core-winrt-error-l1-1-0.dll" "system" fn RoOriginateError(error : HRESULT, message : * mut::core::ffi::c_void) -> BOOL);
::windows_targets::link!("api-ms-win-core-winrt-l1-1-0.dll" "system" fn RoGetActivationFactory(activatableclassid : * mut::core::ffi::c_void, iid : *const GUID, factory : *mut *mut ::core::ffi::c_void) -> HRESULT);
::windows_targets::link!("kernel32.dll" "system" fn CloseHandle(hobject : HANDLE) -> BOOL);
::windows_targets::link!("kernel32.dll" "system" fn CreateEventW(lpeventattributes : *const SECURITY_ATTRIBUTES, bmanualreset : BOOL, binitialstate : BOOL, lpname : PCWSTR) -> HANDLE);
::windows_targets::link!("kernel32.dll" "system" fn EncodePointer(ptr : *const ::core::ffi::c_void) -> *mut ::core::ffi::c_void);
Expand Down Expand Up @@ -549,7 +549,6 @@ pub type HANDLE = isize;
pub type HEAP_FLAGS = u32;
pub type HMODULE = isize;
pub type HRESULT = i32;
pub type HSTRING = *mut ::core::ffi::c_void;
#[repr(C)]
pub struct IDLDESC {
pub dwReserved: usize,
Expand All @@ -564,7 +563,6 @@ impl ::core::clone::Clone for IDLDESC {
pub type IDLFLAGS = u16;
pub type IMPLTYPEFLAGS = i32;
pub type INVOKEKIND = i32;
pub type IUnknown = *mut ::core::ffi::c_void;
pub type LOAD_LIBRARY_FLAGS = u32;
pub const LOAD_LIBRARY_SEARCH_DEFAULT_DIRS: LOAD_LIBRARY_FLAGS = 4096u32;
pub type LPEXCEPFINO_DEFERRED_FILLIN = ::core::option::Option<unsafe extern "system" fn(pexcepinfo: *mut EXCEPINFO) -> HRESULT>;
Expand Down Expand Up @@ -655,7 +653,7 @@ pub union PROPVARIANT_0_0_0 {
pub blob: BLOB,
pub pszVal: PSTR,
pub pwszVal: PWSTR,
pub punkVal: IUnknown,
pub punkVal: *mut ::core::ffi::c_void,
pub pdispVal: *mut ::core::ffi::c_void,
pub pStream: *mut ::core::ffi::c_void,
pub pStorage: *mut ::core::ffi::c_void,
Expand Down Expand Up @@ -699,7 +697,7 @@ pub union PROPVARIANT_0_0_0 {
pub pcyVal: *mut CY,
pub pdate: *mut f64,
pub pbstrVal: *mut BSTR,
pub ppunkVal: *mut IUnknown,
pub ppunkVal: *mut *mut ::core::ffi::c_void,
pub ppdispVal: *mut *mut ::core::ffi::c_void,
pub pparray: *mut *mut SAFEARRAY,
pub pvarVal: *mut PROPVARIANT,
Expand Down Expand Up @@ -918,7 +916,7 @@ pub union VARIANT_0_0_0 {
pub cyVal: CY,
pub date: f64,
pub bstrVal: BSTR,
pub punkVal: IUnknown,
pub punkVal: *mut ::core::ffi::c_void,
pub pdispVal: *mut ::core::ffi::c_void,
pub parray: *mut SAFEARRAY,
pub pbVal: *mut u8,
Expand All @@ -933,7 +931,7 @@ pub union VARIANT_0_0_0 {
pub pcyVal: *mut CY,
pub pdate: *mut f64,
pub pbstrVal: *mut BSTR,
pub ppunkVal: *mut IUnknown,
pub ppunkVal: *mut *mut ::core::ffi::c_void,
pub ppdispVal: *mut *mut ::core::ffi::c_void,
pub pparray: *mut *mut SAFEARRAY,
pub pvarVal: *mut VARIANT,
Expand Down
Loading

0 comments on commit a86c71a

Please sign in to comment.