Generated view structs (FooView<'a>, FooLazyView<'a>) and owned message structs are emitted as plain pub struct with all-pub fields. Any addition of a field is therefore a compile-breaking change for downstream code that constructs these types with an exhaustive struct literal (no ..Default::default()) or destructures them exhaustively.
Two recent changes make this more than a theoretical concern:
The same property applies to ordinary schema evolution: adding a field to a message in the .proto breaks exhaustive literals of the owned struct, which is conventional for protobuf codegen (prost behaves the same way), but we have never stated a policy.
Options
#[non_exhaustive] on generated view structs. Makes the rule compiler-enforced, but prohibits struct-literal construction outside the generated crate entirely — including Foo { x, ..Default::default() } — which breaks the legitimate "hand-build a view to encode it" use-case and every existing test that constructs views literally.
- Document the policy (views and owned messages are constructed via
decode/Default/setters; exhaustive literals are not covered by semver) without changing codegen.
- Generated constructors/builders for views, paired with either option 1 or 2, so there is an ergonomic non-literal construction path before any enforcement lands.
Option 1 alone is probably too blunt for the current API; some combination of 2 now and 3 later seems more plausible. Worth deciding before the 0.8.0 line stabilises, since whichever rule we pick shapes what counts as a breaking change for every release after it.
Generated view structs (
FooView<'a>,FooLazyView<'a>) and owned message structs are emitted as plainpub structwith all-pubfields. Any addition of a field is therefore a compile-breaking change for downstream code that constructs these types with an exhaustive struct literal (no..Default::default()) or destructures them exhaustively.Two recent changes make this more than a theoretical concern:
__buffa_unknown_fieldshandling and the lazy view family.#[doc(hidden)] pub __buffa_required_seen_N: u64bookkeeping words to views of messages with proto2/editions required fields. A consumer who built such a view with an exhaustive literal on the previous release fails to compile after upgrading, even though their.protodid not change.The same property applies to ordinary schema evolution: adding a field to a message in the
.protobreaks exhaustive literals of the owned struct, which is conventional for protobuf codegen (prost behaves the same way), but we have never stated a policy.Options
#[non_exhaustive]on generated view structs. Makes the rule compiler-enforced, but prohibits struct-literal construction outside the generated crate entirely — includingFoo { x, ..Default::default() }— which breaks the legitimate "hand-build a view to encode it" use-case and every existing test that constructs views literally.decode/Default/setters; exhaustive literals are not covered by semver) without changing codegen.Option 1 alone is probably too blunt for the current API; some combination of 2 now and 3 later seems more plausible. Worth deciding before the 0.8.0 line stabilises, since whichever rule we pick shapes what counts as a breaking change for every release after it.