Skip to content

view: give a missing required field its declared default - #807

Open
v0ropaev wants to merge 1 commit into
anthropics:mainfrom
v0ropaev:fix/view-required-default
Open

v0ropaev wants to merge 1 commit into
anthropics:mainfrom
v0ropaev:fix/view-required-default

Conversation

@v0ropaev

Copy link
Copy Markdown
Contributor

When a proto2 required field (or an editions LEGACY_REQUIRED one) declares [default = X], the owned struct gets a hand-written Default that starts the field at X, so Message::decode of input without the field gives X back. The eager and lazy views derived Default instead, unless an enum-type override had opened a required enum, so the same field held the type's zero value. For the same bytes the view, its re-encoding and to_owned_message() then disagreed with owned decode. With the existing RequiredDefaults fixture:

let owned = RequiredDefaults::decode_from_slice(&[]).unwrap();
let view = RequiredDefaultsView::decode_view(&[]).unwrap();
assert_eq!(owned.count, 42);
assert_eq!(view.count, 42); // was 0
assert_eq!(view.level, Priority::CRITICAL); // was LOW
// view.encode_to_vec() wrote 08 00 where the owned encoding writes 08 2a

C++ after ParsePartial and Go after an AllowPartial unmarshal also return the declared default from their getters.

custom_view_default_impl now fills these fields from their declared default, under the same gate the owned Default uses (explicit presence on the message, or an opened enum). View strings and bytes borrow, so they get a 'static literal, and a string that strict_utf8_mapping turned into bytes keeps its text as UTF-8. Every other type reuses parse_default_value, and the opened-enum path is unchanged. The lazy view picks this up through the same function.

The new tests check the view values for an empty buffer and a partial one, and check that to_owned_message() and the view's own encoding match owned decode. They cover RequiredDefaults, RequiredBytesDefaults with its nested message in the three bytes configurations, KeywordEnumDefault on the lazy view, and the editions LEGACY_REQUIRED fixture in utf8_validation.proto. Checked-in generated code doesn't change.

@github-actions

Copy link
Copy Markdown

All contributors have signed the CLA ✍️ ✅
Posted by the CLA Assistant Lite bot.

The owned struct of a message whose proto2 `required` or editions
`LEGACY_REQUIRED` field declares `[default = X]` gets a hand-written
`Default` that starts the field at X, so `Message::decode` of input
without the field returns X. The eager and lazy views derived `Default`
unless an enum-type override opened a required enum, so the same field
held the type's zero value. For one input the view, its re-encoding and
`to_owned_message()` then disagreed with `Message::decode`: with
`required int32 count = 1 [default = 42]` and an empty buffer, owned
decode gave 42 and `decode_view(..).to_owned_message()` gave 0.

`custom_view_default_impl` now initializes these fields from their
declared default, under the same gate the owned `Default` uses. Strings
and bytes get a `'static` literal because view fields borrow; every other
type reuses `parse_default_value`. The opened-enum path is unchanged.
@v0ropaev
v0ropaev force-pushed the fix/view-required-default branch from d49378b to 5d44450 Compare October 28, 2026 12:24

This branch has not been deployed

No deployments
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.

1 participant