Skip to content

windows-core: declarative interface_decl! macro_rules alternative to #[interface] - #4403

Merged
Kenny Kerr (kennykerr) merged 14 commits into
masterfrom
copilot/analyze-implement-interface-macros
May 12, 2026
Merged

windows-core: declarative interface_decl! macro_rules alternative to #[interface]#4403
Kenny Kerr (kennykerr) merged 14 commits into
masterfrom
copilot/analyze-implement-interface-macros

Conversation

Copilot AI commented May 11, 2026

Copy link
Copy Markdown
Contributor

Adds macro_rules!-based alternatives to #[interface] / #[implement] in windows-core, migrates the remaining hand-written generic implementers in windows-collections and windows-future over to them, and makes the proc-macros optional so consumers can drop the syn / quote / proc-macro2 build dependencies.

Changes Made

  • interface_decl! — declarative alternative to #[interface] for COM interfaces inheriting directly from IUnknown. The generated interface struct, vtable, _Impl trait, and safe-caller wrappers are always pub (matching define_interface!). Supported method shapes are -> Result<()> (vtable returns HRESULT) and void; value-returning and Result<T> shapes are intentionally not accepted.
  • implement_decl! — declarative alternative to #[implement]. Single macro with two top-level arms:
    • non-generic: impl Name as Vis Name_Impl: [Iface, …]
    • generic: impl<G,…> Name as Vis Name_Impl: [Iface<…>, …] where … (the where clause is mandatory and forwarded verbatim).
      All generic-form helpers live alongside the non-generic helpers in implement_macro.rs (no separate implement_generic_macro.rs). Vtable type for each interface entry is reached via <Iface as Interface>::Vtable, so callers don't spell out _Vtbl idents.
  • Callsite migrations — every hand-written generic implementer in windows-collections (iterable, map, vector, observable_map, observable_vector, vector_view, map_view, key_value_pair) and windows-future (async_ready, async_spawn) now uses implement_decl! instead of bespoke unsafe wiring.
  • Cargo featureswindows-core gains a default-on proc-macros feature that gates the re-exports of #[implement] / #[interface]. windows-collections and windows-future disable default features so they no longer pull in the proc-macro toolchain. The top-level windows crate keeps windows-core/proc-macros enabled by default for backwards compatibility.
  • Test coverage — new integration test crates/tests/libs/interface_core/tests/macro_rules_decl.rs exercises both interface_decl! and implement_decl! end-to-end (multi-interface implementer, QueryInterface across the chain, refcount drop, IID matching).

Testing

  • cargo check -p windows-core -p windows-collections -p windows-future passes
  • cargo test -p test_interface_core -p test_collections passes (4/4 in macro_rules_decl)
  • parallel_validation (Code Review + CodeQL) clean

Copilot AI and others added 2 commits May 11, 2026 18:38

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

Adds macro_rules!-based alternatives to #[interface] / #[implement] in windows-core, migrates remaining hand-written implementers to the declarative macros, and adjusts feature flags so consumers can opt out of proc-macro dependencies.

Changes:

  • Introduce interface_decl!, implement_decl!, and implement_decl_generic! in windows-core.
  • Port several windows-collections / windows-future types from #[implement] to the new declarative macros.
  • Update Cargo feature wiring to make proc-macros optional and fix test/CI configuration.

Reviewed changes

Copilot reviewed 24 out of 24 changed files in this pull request and generated 10 comments.

Show a summary per file
File Description
crates/tests/misc/no_std/Cargo.toml Enables windows-core/proc-macros for the no-std test crate.
crates/tests/misc/linux/Cargo.toml Enables windows-core/proc-macros for the linux misc test crate.
crates/tests/libs/interface_core/tests/macro_rules_decl.rs New tests exercising interface_decl!/implement_decl! interoperability and ABI basics.
crates/tests/libs/interface_core/Cargo.toml Enables windows-core/proc-macros feature for interface_core tests.
crates/tests/libs/implement_core/Cargo.toml Enables windows-core/proc-macros feature for implement_core tests.
crates/tests/libs/collections/Cargo.toml Enables windows-core/proc-macros feature for collections tests.
crates/libs/windows/Cargo.toml Changes default features to include windows-core/proc-macros.
crates/libs/future/src/async_spawn.rs Ports async implementers from #[implement] to implement_decl!/implement_decl_generic!.
crates/libs/future/src/async_ready.rs Ports ready-state implementers from #[implement] to implement_decl!/implement_decl_generic!.
crates/libs/future/Cargo.toml Disables windows-core default features for windows-future.
crates/libs/core/src/lib.rs Adds new macro modules and gates proc-macro re-exports behind proc-macros feature.
crates/libs/core/src/interface_macro.rs Adds interface_decl! + helpers to declare interfaces without proc macros.
crates/libs/core/src/implement_macro.rs Adds implement_decl! + helpers to wire non-generic implementers without proc macros.
crates/libs/core/src/implement_generic_macro.rs Adds implement_decl_generic! for generic implementers without proc macros.
crates/libs/core/Cargo.toml Makes proc-macro deps optional and adds proc-macros feature (enabled by default).
crates/libs/collections/src/vector_view.rs Ports #[implement] sites to implement_decl_generic!.
crates/libs/collections/src/vector.rs Ports #[implement] sites to implement_decl_generic!.
crates/libs/collections/src/observable_vector.rs Ports #[implement] sites to implement_decl_generic!/implement_decl!.
crates/libs/collections/src/observable_map.rs Ports #[implement] sites to implement_decl_generic!.
crates/libs/collections/src/map_view.rs Ports #[implement] sites to implement_decl_generic!.
crates/libs/collections/src/map.rs Ports #[implement] sites to implement_decl_generic!.
crates/libs/collections/src/key_value_pair.rs Ports #[implement] sites to implement_decl_generic!.
crates/libs/collections/src/iterable.rs Ports #[implement] sites to implement_decl_generic!.
crates/libs/collections/Cargo.toml Disables windows-core default features for windows-collections.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread crates/libs/core/src/interface_macro.rs Outdated
Comment on lines +121 to +125
$vis unsafe fn $mname(&self $(, $aname: $aty)*) -> $crate::Result<$res> {
unsafe {
($crate::Interface::vtable(self).$mname)($crate::Interface::as_raw(self) $(, $aname)*).ok()
}
}
let this_outer: &Identity = unsafe {
&*((this as *const *const ()).offset(OFFSET) as *const Identity)
};
unsafe { <Identity as $impl_trait>::$mname(this_outer $(, $aname)*) }.into()

[dependencies.windows-core]
workspace = true
features = ["proc-macros"]

[features]
default = ["std"]
default = ["std", "windows-core/proc-macros"]
Comment on lines +456 to +459
macro_rules! __implement_decl_offset_negate {
(()) => {
-1isize
};
Comment on lines +503 to +507
-16isize
}; // Hand-written implementers rarely declare more than a handful of interfaces; the
// hard cap is more than the practical maximum. If you hit this, split your
// implementation across multiple objects or use the proc-macro.
}
Comment on lines +589 to +592
macro_rules! __implement_decl_index_plus_two {
() => {
2usize
};
};
(() () () () () () () () () () () () () () ()) => {
17usize
};
Comment on lines +51 to +54
// Each interface needs an internal field/const name on the generated wrapper. The
// names are never user-visible (no item generated by this macro lets external code
// refer to them), so we draw them from a fixed anonymous pool. The pool size
// matches the cap in `__implement_decl_offset_negate!`.
Comment thread crates/libs/core/src/interface_macro.rs Outdated
Comment on lines +196 to +199
// this macro accumulates four token lists (vtbl fields, vtbl initializers, thunk fn defs,
// and matches-arms for parent chain traversal — currently unused but reserved for a
// future extension) and emits the whole `struct $vtbl { ... } impl $vtbl { ... }` block
// at the end.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 23 out of 23 changed files in this pull request and generated 5 comments.

Comment on lines +55 to +65
macro_rules! interface_decl {
(
$(#[doc = $doc:expr])*
$vis:vis unsafe trait $name:ident ( $vtbl:ident, $impl_trait:ident ) : $parent:ty = $iid:literal {
$($methods:tt)*
}
) => {
// Struct + Interface + Debug.
$crate::imp::define_interface!($name, $vtbl, $iid);
// CanInto + From conversions to ancestors.
$crate::imp::interface_hierarchy!($name, $parent);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't bother capturing docs at all.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 2268a7a — the doc capture is gone from interface_decl! and both helper macros.

Comment thread crates/libs/core/src/interface_macro.rs Outdated
Comment on lines +131 to +139
($vis:vis,
$(#[doc = $mdoc:expr])*
unsafe fn $mname:ident (&self $(, $aname:ident : $aty:ty)* $(,)? ) -> $ret:ty ;
$($rest:tt)*
) => {
$(#[doc = $mdoc])*
#[inline]
$vis unsafe fn $mname(&self $(, $aname: $aty)*) -> $ret {
unsafe {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just remove these unused and untested arms.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed in 2268a7a — only Result<()> and void return-type arms remain in the wrapper, trait-method, and vtable helpers. Updated the test to drop the value-returning method.

Comment on lines +873 to +877
#[repr(C)]
#[allow(non_camel_case_types, non_snake_case)]
$impl_vis struct $impl_name < $($gp),+ >
where $($wc)*
{

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's just require the where clause and pass it through as is.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 2268a7a — the where clause is now mandatory and forwarded verbatim. Every existing call site already supplies one.

Comment thread crates/libs/core/src/implement_macro.rs Outdated
Comment on lines +70 to +72
//! The leading ident of every interface entry must be unique within a single invocation —
//! it doubles as the per-chain struct field name and as the name of the per-chain
//! associated constant on `Foo_Impl`.
Comment thread crates/libs/core/src/interface_macro.rs Outdated
Comment on lines +58 to +65
$vis:vis unsafe trait $name:ident ( $vtbl:ident, $impl_trait:ident ) : $parent:ty = $iid:literal {
$($methods:tt)*
}
) => {
// Struct + Interface + Debug.
$crate::imp::define_interface!($name, $vtbl, $iid);
// CanInto + From conversions to ancestors.
$crate::imp::interface_hierarchy!($name, $parent);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just assuming pub as define_interface does is sufficient.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 2268a7a$vis dropped from interface_decl!; the trait, struct, vtable, and wrapper fns are all pub unconditionally.

@kennykerr

Copy link
Copy Markdown
Collaborator

Copilot address new review comments.

@kennykerr
Kenny Kerr (kennykerr) merged commit d20b963 into master May 12, 2026
29 checks passed
@kennykerr
Kenny Kerr (kennykerr) deleted the copilot/analyze-implement-interface-macros branch May 12, 2026 13:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants