Design note to file against microsoft/windows-rs. No code changes in this
repo yet — the work depends on bindgen-side support landing first.
Type-level --filter in crates/tools/bindings/src/main.rs is at its
empirical minimum (see the bindings filter memory: every entry is reachable
from code we actually use). Despite that, crates/libs/reactor/src/bindings.rs
still ships ~32k LoC and ~1,560 pub fns, the bulk of which are unused. Worst
offenders today:
| Interface | Methods generated | Methods we call |
|---|---|---|
IUIElement |
116 | ~5 |
IFrameworkElement |
~100 | ~30 |
IControl |
~70 | ~20 |
IAutomationPeerOverrides |
38 | 0 |
The next lever is method granularity.
windows-bindgen --minimal already demotes vtable slots to anonymous
Foo: usize whenever a method's signature references a type outside
--filter, preserving COM offsets and skipping the matching impl wrapper.
The emit-as-opaque-slot mechanism exists; only a by-name trigger is missing.
Extend the existing --filter to accept method-level entries — no new
options, no config file, no new reporter. Existing callers are unaffected
because the new entries only appear if you write a :: in them.
Ns.Type # keep type, all methods (today's behavior)
Ns.Type::Method # keep this method; demote unlisted methods on Type
Ns.Type::Property # sugar for get_Property + put_Property
Ns.Type::Event # sugar for add_Event + remove_Event
!Ns.Type::Method # exclude (demote) this method; keep rest
!Ns.Type # exclude type (today's behavior — already supported via `!`)
The ! exclude prefix is reused from the existing exclude mechanism; the
only new thing is ::Method after a type name.
- Plain
Ns.Typekeeps current "all methods kept" behavior — fully backwards-compatible. - The first
Ns.Type::…entry for a given type flips that type into allowlist mode: only listed methods are kept, the rest demote toSlot: usize. MultipleNs.Type::Methodentries accumulate. !Ns.Type::Methodis the denylist form: type stays in keep-all mode, only the listed methods demote. Mixing allow + deny entries on the same type is an error.- Property/event sugar expands at parse time.
- Vtable layout sacred. Demoted methods become
Slot: usizeat their exact original offset — same mechanism--minimalalready uses for signature-pruned methods. ABI-safe by construction. - Method filter runs after type filter. Cannot remove types; only methods on already-kept types. Result types referenced only by demoted methods stay kept (no transitive recompute).
- Inheritance opaque. A filter on a derived interface only affects its own slots; base interfaces filter independently.
--implementsoverrides. Methods required by an implemented interface (e.g. ourIApplicationOverrides,IXamlMetadataProvider) are always emitted; explicit exclusion is a hard error.- Unused entries already covered. Filter entries that match nothing show
up in the existing bindgen
Warningsoutput — no new reporter needed.
The per-method decision point in the writer already chooses between typed
slot and usize. Extend the --filter parser to split on ::, record an
optional MethodFilter { Keep(set) | Exclude(set) } per type. In the writer,
after the existing signature-reachability check, consult the filter and
demote rejected methods. Expand property/event sugar at the same place the
writer already collapses get_X / put_X into one pub fn. Skip the
matching impl wrapper (same gate). Short-circuit for --implements
methods. No winmd-schema changes, no offset analysis, no new CLI args.
Modest denylists across the heavy interfaces project to ~15–25% trim of
bindings.rs at zero ABI risk. The win compounds because pruned methods drop
their impl wrappers, agile-call shims, and any reachable-but-otherwise-
unused parameter types.
- Not a security boundary. Demoted offsets are derivable; raw-vtable calls still work. This is a binary-size / compile-time tool, not an API gate — document accordingly.
- Diff churn. Toggling method-filter membership shifts no offsets (slot
stays
: usize), so iteration is safe. - Out of scope: filtering by winmd attribute (
[Deprecated], contract version), struct fields, enum variants.
!Ns.Type::Method(denylist) — lower authoring risk; touch only the heaviest interfaces.Ns.Type::Method(allowlist) — for surgical surfaces likeIAutomationPeerOverrideswhere almost nothing is used.- Property/event sugar.
Add !Ns.Type::Method lines to the existing --filter array in
crates/tools/bindings/src/main.rs per heavy interface, each block
independently verifiable via
cargo check --target x86_64-pc-windows-msvc -p windows-reactor.