-
Notifications
You must be signed in to change notification settings - Fork 465
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
Improve Vtable implementations #1740
Conversation
unsafe extern "system" fn #name<#(#constraints)* Identity: ::windows::core::IUnknownImpl, Impl: #impl_ident<#(#generics)*>, const OFFSET: isize> #vtbl_signature { | ||
let this = (this as *mut ::windows::core::RawPtr).offset(OFFSET) as *mut Identity; | ||
let this = (*this).get_impl() as *mut Impl; | ||
unsafe extern "system" fn #name<#(#constraints)* Identity: ::windows::core::IUnknownImpl<Impl = Impl>, Impl: #impl_ident<#(#generics)*>, const OFFSET: isize> #vtbl_signature { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you help me understand what the IUnknownImpl<Impl = Impl>
syntax means?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure! So the IUnknownImpl
trait now has an associated type with called Impl
which is meant to be the implementation backing the COM object, and is what is returned fromIUnknownImpl::get_impl
. You can see the definition of that here.
The Identity: IUnknownImpl<Impl = Impl>
(yes, that's a lot of impl) syntax means the generic parameter Identity
must implement the trait IUknownImpl
with an associated type that is itself the generic parameter Impl
. So the Impl = Impl
says "the associated type of the IUnknownImpl
trait is called Impl
and we're saying it must be whatever the generic parameter Impl
is.
This would probably be clearer if we used different names for the associated type and the generic parameter. Normally generic parameters are single letters like T
, U
, etc. so the syntax would end up looking like Identity: IUnknownImpl<Impl = I>
.
Does that make sense? Any thoughts on how we can tweak names to make this clearer?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here's a simplified version of what we're doing you can use to play around with how the syntax works.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Got it - thanks! Yes, that's a lot of impl, but then this isn't something that devs need to interact with so perhaps not that important. I'm far more interested in find a way to drop the Impl
from names like IStringable_Impl
that devs need to utter...
Thanks Ryan, this certainly feels less hacky. 👍 |
note: since codegen was run on this PR, it's easier to review commit by commit as code gen is always runs in a separate commit
This PR slightly simplifies vtable implementations while also making them a bit more type and memory safe:
IUnknownImpl::get_impl
to return a reference to the actual implementation type which is not specified as an associated type. This avoids passing a void pointer around which prevents the compiler from doing some type and borrow checking.IUnknownImpl::get_impl
to take a&self
instead of&mut self
. Com interfaces are non-exclusive references to a shared vtable so&mut self
is just wrong and is UB.This change is easiest to see when comparing COM vtable method implementations before and after this change:
Before
After
One additional change I believe we can make is changing the
this
pointers to*const
instead of*mut
.