Skip to content

Targeted Attribute Injection - #1656

Open
wilfreddenton wants to merge 2 commits into
bytecodealliance:mainfrom
wilfreddenton:feat/targeted-attributes
Open

Targeted Attribute Injection#1656
wilfreddenton wants to merge 2 commits into
bytecodealliance:mainfrom
wilfreddenton:feat/targeted-attributes

Conversation

@wilfreddenton

Copy link
Copy Markdown

Targeted version of additional_derives. Instead of hitting every generated type,
you attach attributes to specific types and members. This is an attempt at the path-specific /
with-style derive idea from #1386, #1467, and #812 (also #291, #554).

Two options: additional_type_attributes for records/variants/enums, and
additional_member_attributes for fields and enum/variant cases. Each maps a selector
to a list of attributes, and the selectors are the same keys with uses (bare name,
package, interface, or fully-qualified, with @version when versioned):

wit_bindgen::generate!({
    // ...
    additional_type_attributes: {
        "my:pkg/types/record-name": [r#"#[derive(serde::Serialize)]"#],
        "my:pkg/types": [r#"#[derive(Clone)]"#],          // every type in the interface
    },
    additional_member_attributes: {
        "record-name.field": [r#"#[serde(rename = "f")]"#],
    },
});

Any attribute works, not just derives. An injected #[derive(...)] folds into the
type's generated derive so it dedups against the built-ins and additional_derives
instead of colliding.

Went with two options rather than one nested map to match prost's
type_attribute/field_attribute, keep the CLI flags simple, and avoid a bare name
being ambiguous between a type and a member. A selector that matches nothing is an
error, same as with with unused keys.

Some limits: only records/variants/enums (broad selectors just skip
flags/resources/aliases), attributes land on every ownership form so an owned-only
derive like Deserialize won't compile on a borrowed form, and it's Rust-only for
now following #678/#1199.

Not sure on the naming. additional_* sits next to additional_derives, but it acts
more like with. Happy to switch to type_attributes/member_attributes or whatever
you prefer.

Tests in crates/rust/tests/codegen.rs.

@wilfreddenton
wilfreddenton force-pushed the feat/targeted-attributes branch from bca5742 to 73c9e78 Compare July 15, 2026 13:32
@wilfreddenton
wilfreddenton marked this pull request as ready for review July 16, 2026 16:12
@alexcrichton

Copy link
Copy Markdown
Member

I know I'm taking a bit of time to get to this, sorry about that. This hasn't fallen off my radar, just haven't gotten the time to review it yet

@alexcrichton alexcrichton left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks for the PR again, and apologies for the delay. This all seems reasonable to me but I'd primarily like to integrate the string-selector style syntax with the rest of the macro (as opposed to building something brand new). Could it also be integrated with the unused-attributes warning/error that wit-bindgen emits to catch typos?

Comment thread crates/rust/src/interface.rs Outdated

/// Every selector key that matches type `id`: its identity keys plus its
/// owning interface and package.
fn type_selector_keys(&self, id: TypeId) -> Vec<String> {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'd like to ideally have a relatively central method of specifying strings which identify/map to WIT types. To that extent this is at least somewhat present as full_wit_type_name at the root of the crate and how it affects with. Can that be integrated and/or updated to handle this new use case as well? I woudl prefer to not add another method of identifying types/etc with strings.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Changed this to a thin wit_type_selectors wrapper around full_wit_type_name, which it calls rather than reimplements, so with is untouched. Pushing the coarser forms into with doesn't seem right though: a remapping is 1:1, so a package key would have to map every type in the package to the same Rust path, whereas attributes fan out by design.

Comment thread crates/rust/src/interface.rs Outdated
Comment thread crates/rust/src/interface.rs Outdated
Comment thread crates/rust/src/lib.rs Outdated
Comment thread crates/rust/tests/codegen.rs Outdated
Comment thread crates/rust/src/lib.rs Outdated
@wilfreddenton
wilfreddenton force-pushed the feat/targeted-attributes branch from 73c9e78 to acab6ef Compare July 28, 2026 04:38
@wilfreddenton
wilfreddenton force-pushed the feat/targeted-attributes branch from acab6ef to 3f4ae8f Compare July 28, 2026 04:54
@wilfreddenton

Copy link
Copy Markdown
Author

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.

2 participants