Repository navigation
codegen: oneof_struct_field_attribute for the struct field holding a oneof - #561
benedikt-bartscher wants to merge 4 commits into
Conversation
|
All contributors have signed the CLA ✍️ ✅ |
field_attribute never reaches the struct's Option<OneofEnum> field: on the oneof's path it matches only the variants, where an attribute such as #[serde(skip_serializing_if = "...")] is rejected. prost-build put such a field_attribute on the struct field as well.
eeb3bdd to
0b99080
Compare
|
[claude code] Thanks for this, and for raising the naming question in the description. Yes, please rename it: The reason is the one you gave. The branch also conflicts with With the rename and the rebase it is ready for a full review. |
# Conflicts: # buffa-codegen/src/message.rs
`oneof_field_attribute` reads as "an attribute on a oneof's member field", which is what the paths given to `unbox_oneof_in` mean (`.pkg.Msg.my_oneof.variant`). A rule written with such a member path matches no oneof and silently does nothing. `Config::oneof_struct_field_attribute` and `CodeGenConfig::oneof_struct_field_attributes` name the target instead: the message struct's field that holds the oneof, matched by the oneof's own path.
A `#[deprecated]` given through `oneof_struct_field_attribute` now puts `#[allow(deprecated)]` on the generated impls that visit the oneof's struct field, as a `#[deprecated]` from `field_attribute` does for a plain field. Output is unchanged when no such rule exists. The codegen tests parse the generated files and assert the exact attribute list on the oneof field: placement next to a plain field, order after `serde(flatten)` and after the keyword-rename doc note, prefix and catch-all rules, segment-boundary and variant-path non-matches, a proto3 `optional` field beside a real oneof, rule accumulation order, and the error for a malformed attribute. buffa-test compiles two fixtures: a oneof whose struct field is deprecated through the option, with views, lazy views, text, JSON and reflection on, and a message with a caller-derived `serde::Serialize` whose oneof field takes `skip_serializing_if`. The method doc maps `oneof_struct_field_attribute`, `oneof_attribute` and `field_attribute` to the generated lines they reach, states that a variant path has no effect, and adds a Pitfalls section for `generate_json` and feature-gated impls. Its example turns unknown-field preservation off, because `UnknownFields` does not implement `serde::Serialize`.
|
[claude code] To close this out sooner, the rename asked for above is now on this branch, together with a merge of
The prost parity claim holds in prost-build 0.14.4: |
field_attributenever reaches the struct field that holds a oneof, theOption<OneofEnum>member. On the path of the oneof it matches only the variants (.pkg.Msg.oneof.variant), so that field cannot carry an attribute of its own. The case that needs one is serde:#[serde(skip_serializing_if = "Option::is_none")]belongs on the struct field, and serde rejects it on enum variants. prost-build puts afield_attributeon the path of a oneof on the struct field and on every variant, so a project moving from prost loses that attribute with no replacement.This adds
Config::oneof_struct_field_attribute(path, attribute)/CodeGenConfig::oneof_struct_field_attributes. It is matched against the path of the oneof likeoneof_attributeand applies to the field of the owned struct only. A variant path does not match the oneof, so a rule written with one has no effect.Changes:
message.rsemits the matching attributes on the oneof field, after the keyword-rename doc note and the#[serde(flatten)]that buffa adds. View structs get none, like the rest of the attribute family. A malformed attribute fails withInvalidCustomAttribute, as for the other lists. A#[deprecated]given through the option puts#[allow(deprecated)]on the generated impls that read the field, as one fromfield_attributedoes for a plain field.oneof_struct_field_attribute, with an example, a map of which of the three attribute methods reaches which generated line, and a Pitfalls section forgenerate_json. The example turns unknown-field preservation off, becauseUnknownFieldsdoes not implementserde::Serialize. Thefield_attributeandoneof_attributedocs point to the new method.docs/guide.md, and thefield_attributerow indocs/migration-from-prost.md, which said "Same API" and now names the difference on the path of a oneof.optionalfield beside a real oneof, and two rules on one field.buffa-testcompiles a caller-derivedserde::Serializewithskip_serializing_ifon the oneof field, and a oneof field deprecated through the option.On the name:
unbox_oneof_inandfield_attributetake the path of a member of a oneof, so "oneof field" reads as a member.oneof_struct_field_attributenames the struct field that holds the oneof.