Skip to content

Add enum_attribute API for enum-only Rust attributes#50

Merged
iainmcgin merged 2 commits intomainfrom
feat/enum-attribute
Apr 17, 2026
Merged

Add enum_attribute API for enum-only Rust attributes#50
iainmcgin merged 2 commits intomainfrom
feat/enum-attribute

Conversation

@iainmcgin
Copy link
Copy Markdown
Collaborator

Follow-up to #44, partly addressing #23.

The custom-attributes API from #44 has type_attribute (matches both messages and enums) and message_attribute (struct-only), but no symmetric enum-only filter. Users wanting to inject a derive like #[derive(strum::EnumIter)] on enums had to either also paint every matching message with the same attribute (which usually fails to compile, since the derive only makes sense on enums) or hand-construct an awkward union of multiple .type_attribute(".pkg.MyEnum1", ...) / .type_attribute(".pkg.MyEnum2", ...) matchers.

enum_attribute is the symmetric inverse of message_attribute.

API

buffa_build::Config::new()
    .enum_attribute(".my.pkg", "#[derive(strum::EnumIter)]")
    .files(&["proto/my_service.proto"])
    .includes(&["proto/"])
    .compile()
    .unwrap();

Same path-matching, normalization (leading-dot prepend, trailing-dot trim, segment-aware prefix), insertion-order accumulation, and CodeGenError::InvalidCustomAttribute semantics as the existing trio.

Codegen

In enumeration.rs, after the existing type_attribute match, also match enum_attributes and emit both attribute streams above the pub enum declaration. type_attribute continues to apply to enums as well — enum_attribute is additive, not exclusive.

Tests

  • test_enum_attribute_on_enum_not_struct — catch-all enum_attribute lands on the enum but not on a sibling message struct.
  • test_enum_attribute_scoped_to_specific_enum — prefix-targeted attribute lands on the matched enum only.
  • test_enum_attribute_does_not_apply_to_struct — defense-in-depth check on the non-bleed property.
  • enum_attribute_forwards_normalized_path — build-layer test confirming path normalization and that the other three attribute lists remain untouched.

Workspace tests, clippy -D warnings, rustfmt clean. No codegen drift.

Relation to #23

#23 originally asked for enum_attribute as a way to inject #[derive(strum::EnumIter)]. PR #49 (currently in flight) addresses the underlying use case directly by adding Enumeration::values(), removing the need for the third-party EnumIter derive in most cases. This PR adds enum_attribute because the API symmetry is still genuinely useful (e.g. for serde, schemars, custom derives) and the absence was an asymmetry surprise.

The custom-attributes API from #44 has type_attribute (matches
both messages and enums) and message_attribute (struct-only), but no
symmetric enum-only filter. Users wanting to inject derives like
#[derive(strum::EnumIter)] on enums had to either also paint every
matching message with the same attribute or build an awkward union
of multiple specific type matchers. Add enum_attribute as the
inverse of message_attribute.

- New CodeGenConfig::enum_attributes field, populated by the new
  buffa-build::Config::enum_attribute builder method.
- Wired into enumeration.rs codegen alongside the existing
  type_attributes match — emitted in addition to (not instead of)
  type-attribute output, so users get both layers if they want.
- Same path-matching, normalization, and error semantics as the
  existing trio.

Tests cover: enum-only landing, scoping to a specific enum,
non-bleed onto sibling messages, and the build-layer normalization.
@iainmcgin iainmcgin marked this pull request as ready for review April 16, 2026 23:35
@iainmcgin iainmcgin enabled auto-merge (squash) April 17, 2026 18:58
@iainmcgin iainmcgin merged commit fc7ceb5 into main Apr 17, 2026
7 checks passed
@iainmcgin iainmcgin deleted the feat/enum-attribute branch April 17, 2026 19:01
@github-actions github-actions bot locked and limited conversation to collaborators Apr 17, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants