Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add "vtbl" option for low-level interface vtable generation #2845

Merged
merged 6 commits into from
Feb 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
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