Skip to content

Commit

Permalink
Add support for non-COM interfaces (#2066)
Browse files Browse the repository at this point in the history
  • Loading branch information
kennykerr authored Sep 26, 2022
1 parent d0ab3b5 commit d7343bc
Show file tree
Hide file tree
Showing 31 changed files with 2,667 additions and 1,697 deletions.
2 changes: 1 addition & 1 deletion crates/libs/bindgen/src/classes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ fn gen_class(gen: &Gen, def: TypeDef) -> TokenStream {

tokens.combine(&gen.interface_core_traits(def, &[], &name, &TokenStream::new(), &TokenStream::new(), &features));
tokens.combine(&gen.interface_winrt_trait(def, &[], &name, &TokenStream::new(), &TokenStream::new(), &features));
tokens.combine(&gen.interface_trait(def, &[], &name, &TokenStream::new(), &features));
tokens.combine(&gen.interface_trait(def, &[], &name, &TokenStream::new(), &features, true));
tokens.combine(&gen.runtime_name_trait(def, &[], &name, &TokenStream::new(), &features));
tokens.combine(&gen.async_get(def, &[], &name, &TokenStream::new(), &TokenStream::new(), &features));
tokens.combine(&iterators::gen(gen, def, &[], &name, &TokenStream::new(), &TokenStream::new(), &cfg));
Expand Down
2 changes: 1 addition & 1 deletion crates/libs/bindgen/src/delegates.rs
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ fn gen_win_delegate(gen: &Gen, def: TypeDef) -> TokenStream {
};

tokens.combine(&gen.interface_core_traits(def, generics, &ident, &constraints, &phantoms, &features));
tokens.combine(&gen.interface_trait(def, generics, &ident, &constraints, &features));
tokens.combine(&gen.interface_trait(def, generics, &ident, &constraints, &features, true));
tokens.combine(&gen.interface_winrt_trait(def, generics, &ident, &constraints, &phantoms, &features));
tokens.combine(&gen.interface_vtbl(def, generics, &ident, &constraints, &features));
tokens
Expand Down
20 changes: 14 additions & 6 deletions crates/libs/bindgen/src/gen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -707,7 +707,7 @@ impl<'a> Gen<'a> {
}
}

pub fn interface_trait(&self, def: TypeDef, generics: &[Type], ident: &TokenStream, constraints: &TokenStream, features: &TokenStream) -> TokenStream {
pub fn interface_trait(&self, def: TypeDef, generics: &[Type], ident: &TokenStream, constraints: &TokenStream, features: &TokenStream, has_unknown_base: bool) -> TokenStream {
if let Some(default) = self.reader.type_def_default_interface(def) {
let default_name = self.type_name(&default);
let vtbl = self.type_vtbl_name(&default);
Expand Down Expand Up @@ -737,16 +737,24 @@ impl<'a> Gen<'a> {
::windows::core::GUID::from_signature(<Self as ::windows::core::RuntimeType>::SIGNATURE)
}
};
quote! {

let mut tokens = quote! {
#features
unsafe impl<#constraints> ::windows::core::Vtable for #ident {
type Vtable = #vtbl;
}
#features
unsafe impl<#constraints> ::windows::core::Interface for #ident {
const IID: ::windows::core::GUID = #guid;
}
};

if has_unknown_base {
tokens.combine(&quote! {
#features
unsafe impl<#constraints> ::windows::core::Interface for #ident {
const IID: ::windows::core::GUID = #guid;
}
});
}

tokens
}
}
pub fn interface_vtbl(&self, def: TypeDef, generics: &[Type], _ident: &TokenStream, constraints: &TokenStream, features: &TokenStream) -> TokenStream {
Expand Down
100 changes: 77 additions & 23 deletions crates/libs/bindgen/src/implements.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ pub fn gen(gen: &Gen, def: TypeDef) -> TokenStream {
let type_ident = to_ident(gen.reader.type_def_name(def));
let impl_ident = type_ident.join("_Impl");
let vtbl_ident = type_ident.join("_Vtbl");
let implvtbl_ident = impl_ident.join("Vtbl");
let constraints = gen.generic_constraints(generics);
let generic_names = gen.generic_names(generics);
let named_phantoms = gen.generic_named_phantoms(generics);
Expand All @@ -17,6 +18,7 @@ pub fn gen(gen: &Gen, def: TypeDef) -> TokenStream {
let mut requires = quote! {};
let type_ident = quote! { #type_ident<#generic_names> };
let vtables = gen.reader.type_def_vtables(def);
let has_unknown_base = matches!(vtables.first(), Some(Type::IUnknown));

fn gen_required_trait(gen: &Gen, def: TypeDef, generics: &[Type]) -> TokenStream {
let name = gen.type_def_name_imp(def, generics, "_Impl");
Expand Down Expand Up @@ -83,24 +85,38 @@ pub fn gen(gen: &Gen, def: TypeDef) -> TokenStream {

let invoke_upcall = if gen.reader.type_def_flags(def).winrt() { winrt_methods::gen_upcall(gen, &signature, quote! { this.#name }) } else { com_methods::gen_upcall(gen, &signature, quote! { this.#name }) };

quote! {
unsafe extern "system" fn #name<#constraints Identity: ::windows::core::IUnknownImpl<Impl = Impl>, Impl: #impl_ident<#generic_names>, const OFFSET: isize> #vtbl_signature {
// offset the `this` pointer by `OFFSET` times the size of a pointer and cast it as an IUnknown implementation
let this = (this as *const *const ()).offset(OFFSET) as *const Identity;
let this = (*this).get_impl();
#invoke_upcall
if has_unknown_base {
quote! {
unsafe extern "system" fn #name<#constraints Identity: ::windows::core::IUnknownImpl<Impl = Impl>, Impl: #impl_ident<#generic_names>, const OFFSET: isize> #vtbl_signature {
// offset the `this` pointer by `OFFSET` times the size of a pointer and cast it as an IUnknown implementation
let this = (this as *const *const ()).offset(OFFSET) as *const Identity;
let this = (*this).get_impl();
#invoke_upcall
}
}
} else {
quote! {
unsafe extern "system" fn #name<Impl: #impl_ident> #vtbl_signature {
let this = (this as *mut *mut ::core::ffi::c_void) as *const ::windows::core::ScopedHeap;
let this = &*((*this).this as *const Impl);
#invoke_upcall
}
}
}
});

let mut methods = quote! {};

match gen.reader.type_def_vtables(def).last() {
match vtables.last() {
Some(Type::IUnknown) => methods.combine(&quote! { base__: ::windows::core::IUnknown_Vtbl::new::<Identity, OFFSET>(), }),
Some(Type::IInspectable) => methods.combine(&quote! { base__: ::windows::core::IInspectable_Vtbl::new::<Identity, #type_ident, OFFSET>(), }),
Some(Type::TypeDef((def, generics))) => {
let name = gen.type_def_name_imp(*def, generics, "_Vtbl");
methods.combine(&quote! { base__: #name::new::<Identity, Impl, OFFSET>(), });
if has_unknown_base {
methods.combine(&quote! { base__: #name::new::<Identity, Impl, OFFSET>(), });
} else {
methods.combine(&quote! { base__: #name::new::<Impl>(), });
}
}
_ => {}
}
Expand All @@ -110,26 +126,64 @@ pub fn gen(gen: &Gen, def: TypeDef) -> TokenStream {

for method in gen.reader.type_def_methods(def) {
let name = method_names.add(gen, method);
methods.combine(&quote! { #name: #name::<#generic_names Identity, Impl, OFFSET>, });
if has_unknown_base {
methods.combine(&quote! { #name: #name::<#generic_names Identity, Impl, OFFSET>, });
} else {
methods.combine(&quote! { #name: #name::<Impl>, });
}
}

quote! {
#features
pub trait #impl_ident<#generic_names> : Sized #requires where #constraints {
#(#method_traits)*
if has_unknown_base {
quote! {
#features
pub trait #impl_ident<#generic_names> : Sized #requires where #constraints {
#(#method_traits)*
}
#runtime_name
#features
impl<#constraints> #vtbl_ident<#generic_names> {
pub const fn new<Identity: ::windows::core::IUnknownImpl<Impl = Impl>, Impl: #impl_ident<#generic_names>, const OFFSET: isize>() -> #vtbl_ident<#generic_names> {
#(#method_impls)*
Self{
#methods
#(#named_phantoms)*
}
}
pub fn matches(iid: &windows::core::GUID) -> bool {
#matches
}
}
}
#runtime_name
#features
impl<#constraints> #vtbl_ident<#generic_names> {
pub const fn new<Identity: ::windows::core::IUnknownImpl<Impl = Impl>, Impl: #impl_ident<#generic_names>, const OFFSET: isize>() -> #vtbl_ident<#generic_names> {
#(#method_impls)*
Self{
#methods
#(#named_phantoms)*
} else {
quote! {
#features
pub trait #impl_ident : Sized #requires {
#(#method_traits)*
}
#features
impl #vtbl_ident {
pub const fn new<Impl: #impl_ident>() -> #vtbl_ident {
#(#method_impls)*
Self{
#methods
#(#named_phantoms)*
}
}
}
pub fn matches(iid: &windows::core::GUID) -> bool {
#matches
#[doc(hidden)]
#features
struct #implvtbl_ident<T: #impl_ident> (::std::marker::PhantomData<T>);
#features
impl<T: #impl_ident> #implvtbl_ident<T> {
const VTABLE: #vtbl_ident = #vtbl_ident::new::<T>();
}
#features
impl #type_ident {
pub fn new<'a, T: #impl_ident>(this: &'a T) -> ::windows::core::ScopedInterface<'a, Self> {
let this = ::windows::core::ScopedHeap { vtable: &#implvtbl_ident::<T>::VTABLE as *const _ as *const _, this: this as *const _ as *const _ };
let this = ::std::mem::ManuallyDrop::new(::std::boxed::Box::new(this));
unsafe { ::windows::core::ScopedInterface::new(::std::mem::transmute(&this.vtable)) }
}
}
}
}
Expand Down
Loading

0 comments on commit d7343bc

Please sign in to comment.