Skip to content

OwnedView: remove Deref, add generated FooOwnedView accessor wrappers#154

Merged
iainmcgin merged 3 commits into
mainfrom
owned-view-accessors
May 28, 2026
Merged

OwnedView: remove Deref, add generated FooOwnedView accessor wrappers#154
iainmcgin merged 3 commits into
mainfrom
owned-view-accessors

Conversation

@iainmcgin
Copy link
Copy Markdown
Collaborator

Summary

OwnedView<V> previously implemented Deref<Target = V>. The stored view is FooView<'static>, where the 'static is synthetic — the borrows actually point into the handle's Bytes buffer. Through Deref, safe code could copy borrowed fields (&'static str, &'static [u8]) out of the handle and keep them after the handle dropped, at which point they dangle. Triggering this requires the calling application to deliberately hold a field reference beyond the handle's lifetime, so the practical exposure is limited — but the API should not permit it at all.

This PR:

  • removes the Deref impl; access goes through the existing reborrow(), which ties every borrow to the handle, with a compile_fail doctest pinning the removal (buffa/src/view.rs);
  • adds generated FooOwnedView wrapper types: a per-message newtype around OwnedView<FooView<'static>> with one &self-tied accessor per field (owned.name(), owned.id(), …), plus decode / decode_with_options / from_owned / view() / to_owned_message / bytes / into_bytes, From conversions to and from the raw OwnedView, and JSON Serialize forwarding. The wrapper is re-exported at the package root next to Foo and FooView. reborrow() is a pure lifetime coercion, so the accessors compile to the same code as the old direct field access;
  • regenerates the checked-in WKT and bootstrap descriptor code, and updates the guide, README, DESIGN, prost-migration doc, and CHANGELOG.

Breaking change

owned.field no longer compiles on OwnedView. Migrate either with owned.reborrow().field (or once per scope: let view = owned.reborrow();), or by switching to the generated FooOwnedView and using owned.field(). serde_json::to_string(&owned_view) on the handle is unchanged.

Notes

  • Wrapper generation is tied to generate_views; there is no separate knob, so generated-code size grows accordingly.
  • A field or oneof named like a reserved wrapper method (bytes, view, decode, …) keeps working through view(); its accessor is skipped with a build warning (CodeGenWarning::OwnedViewAccessorSuppressed).
  • The conformance suite is unaffected (the harness never used Deref on OwnedView).

iainmcgin added 3 commits May 28, 2026 02:22
The Deref<Target = V> impl exposed the inner view as FooView<'static>,
so borrowed fields appeared 'static to the borrow checker and could be
held past the point where the OwnedView and its Bytes buffer were
dropped. Field access now goes through reborrow(), which ties every
borrow to the handle. The Serialize impl forwards via the inner view
directly, and a compile_fail doctest pins that field access on the
handle no longer compiles.
For each message (when views are generated, excluding map entries),
emit a FooOwnedView newtype around OwnedView<FooView<'static>> with one
&self-tied accessor method per field, plus decode, decode_with_options,
from_owned, view(), to_owned_message, bytes, into_bytes, From
conversions to and from the raw OwnedView, and a Serialize forwarding
impl when JSON generation is enabled. The wrapper is re-exported at the
package root next to Foo and FooView.

A field or oneof whose name collides with a reserved wrapper method
keeps working through view(); its accessor is skipped with the new
CodeGenWarning::OwnedViewAccessorSuppressed. The view type helpers now
take the borrow lifetime as a parameter so accessor return types can
use the anonymous lifetime.

Regenerates checked-in WKT and bootstrap descriptor types.
Rewrite the OwnedView sections of the guide, README, DESIGN, and the
prost migration doc around reborrow() and the generated FooOwnedView
accessor wrappers, and add CHANGELOG entries for the Deref removal and
the new wrapper types.
@github-actions
Copy link
Copy Markdown

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

@iainmcgin iainmcgin marked this pull request as ready for review May 28, 2026 19:55
@iainmcgin iainmcgin merged commit 7dcf50a into main May 28, 2026
7 checks passed
@iainmcgin iainmcgin deleted the owned-view-accessors branch May 28, 2026 19:55
@github-actions github-actions Bot locked and limited conversation to collaborators May 28, 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