-
Notifications
You must be signed in to change notification settings - Fork 585
Simplify and refactor the implement macro
#3507
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
Simplify and refactor the implement macro
#3507
Conversation
|
At an initial reading this PR seems to be doing too much - it would be easier to reason about if this were broken up a bit more into more discrete changes that focused on individual things. Philosophical changes to |
This sounds like a good meaty PR on its own. I like the sound of this.
Macros seem like they have so much potential in Rust but lack so much in terms of debuggability and testability and contextual ignorance. It would be nice, for consistency to move this into the
There might be an issue here if an implementation needs to implement both
Neat, we did this in C++/WinRT and it made big difference.
We may not be super consistent here but it helps to preserve the original API names to avoid confusion and make it easier to search the code base for related code.
👍
I'm not sure I agree with this - the
👍 |
Fortunately, that won't cause a collision. Both interface chains will have a different index, and the generated ident contains the index as well as the name suffix. So this case would generate something like Speaking of tuples, we've been relying on a behavior that is not guaranteed. The compiler is allowed to reorder the fields within a tuple; tuples are How about this:
|
Even when the field is part of a |
|
I believe so, because the layout of types is determined by their definition, but not their context. In this case, we're getting lucky because these definitions are always "a sequence of non-nullable pointer-sized fields". But if we had a tuple like We're just getting lucky right now. ;) |
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.
I think my comments are on existing code which has been moved...
47095b2 to
61e9b32
Compare
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.
Copilot reviewed 4 out of 4 changed files in this pull request and generated no comments.
Comments suppressed due to low confidence (1)
crates/tests/libs/implement_core/src/com_object.rs:437
- The removal of raw pointer assertions in the iunknown_identity test has reduced explicit verification of the canonical IUnknown pointer behavior. Consider reintroducing these assertions or alternative checks to ensure interface pointer integrity.
let app = MyApp::new(0);
c002135 to
cc8115c
Compare
| //! These tests are just a way to quickly run the `#[implement]` macro and see its output. | ||
| //! They don't check the output in any way. | ||
| //! | ||
| //! This exists because of some difficulties of running `cargo expand` against the `#[implement]` |
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.
Maybe just a comment about how to run a test and see the output - for example I run this:
cargo test -p windows-implement --tests simple_type
But cargo test does not automatically display the stdout for println.
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.
e.g.
cargo test -p windows-implement --tests simple_type -- --nocapture
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.
Much more manageable thanks!
implement macro
This improves COM object support.
The main focus is on improving the internal structure of the
implementproc macro. I've broken theimplementfunction into a bunch of small, focused functions. Theimplementproc macro first parses its input, creates anImplementInputsstruct which contains all of the information need to generate output. Then, it callsgen_allto generate the output, which callsgen_*to generate each specific output item. This makes the code much easier to understand, debug, and edit.The codegen functions (the
gen_*functions) now generate strongly-typedsynvalues, such assyn::Item. Eachgen_*generates the tokens and then parses them into the strongly-typed value. This allows us to catch syntax errors far more quickly, and theparse_quotemacro will panic at the site of any syntax error. This makes development on theincrementmacro a lot more productive.Speaking of debugging, I've added some unit tests within the
implementcrate. They don't actually test anything, but that's not the point. The point of these unit tests is that you can very easily see the output ofimplement, without needingcargo-expand(which has its own problems). You can also step through the code in a debugger.This PR contains some modest improvements to the code that is generated by
implements:interface2_ifoo. This makes it a lot easier to debug COM objects at runtime.IUnknownImpltrait is now anunsafetrait. There's no way to implement this trait without writing unsafe code.IUnknown::Releaseimplementation now puts the "slow" path (refcount reaches zero) into a separate function. This keeps the fast path (refcount is not zero) as small and fast as possible. For objects with significant destructors, this helps.GetTrustLeveland such to use snake casing, where applicable.from_inner_refonIUnknown. There is no need for this any more, since all COM interface method implementations are onFoo_Impltypes now.WeakRefCountthat can change the refcount to haveunsafesignatures. Any change to a refcount could affect memory lifetime, so these operations need to beunsafe. This allows us to expose&WeakRefCountforComObject<T>, which simplifies other things. The motivation here is to make it difficult to accidentally leave a memory safety hole (in safe code).quote_spannedorparse_quote_spannedmacros, with a span that points to the interface name. This improves the error messages when the user forgets to provide an implementation of a COM interface, because the error message will point to the interface name.