From a145824710ba33d589e526db8cf5014a01b8dc66 Mon Sep 17 00:00:00 2001 From: Iain McGinniss <309153+iainmcgin@users.noreply.github.com> Date: Wed, 1 Jul 2026 10:10:26 -0700 Subject: [PATCH 1/2] changelog: record the shipped v0.8.1 maintenance release v0.8.1 was released from the v0.8.x branch (cut from the v0.8.0 tag, so the unreleased breaking changes on main stay out of it). Bring main's changelog up to date: add .changes/0.8.1.md with the released section, fold it into CHANGELOG.md via changie merge, and remove the now-shipped unknown-field accounting fragment from .changes/unreleased so the 0.9.0 release notes do not report the fix a second time. --- .changes/0.8.1.md | 33 ++++++++++++++++++ .../unreleased/fixed-20260701-041207.yaml | 4 --- CHANGELOG.md | 34 +++++++++++++++++++ 3 files changed, 67 insertions(+), 4 deletions(-) create mode 100644 .changes/0.8.1.md delete mode 100644 .changes/unreleased/fixed-20260701-041207.yaml diff --git a/.changes/0.8.1.md b/.changes/0.8.1.md new file mode 100644 index 00000000..a0bf6bf6 --- /dev/null +++ b/.changes/0.8.1.md @@ -0,0 +1,33 @@ +## [0.8.1] - 2026-07-01 + +A single-fix patch release: unknown-field limit accounting for zero-copy +views now matches owned conversion exactly, establishing the guarantee that +a view which decodes successfully always converts to an owned message. No +API changes, and regenerating code is not required — the fix lives in the +runtime. + +### Fixed + +- **Zero-copy view decoding now charges the unknown-field limit per + re-materializable field** — one per unknown record plus, for unknown group + records, one per nested field — instead of one per coalesced span, and + conversion replays under exactly the field budget and group-nesting depth + recorded at decode time (previously a fixed recursion limit, which could + reject deep unknown groups decoded under a raised `with_recursion_limit`). + Decode-time accounting now matches what `to_owned_message` re-materializes, + which gives views a guarantee: **a view produced by `decode_view` always + converts via `to_owned_message` without error** (the `Result` remains for + hand-written impls and `push_raw`-built views). **Behavioral tightening:** + payloads whose unknown-field count exceeds the limit but previously slipped + through view decode via span coalescing — e.g. a ~2 MiB run of >1M + contiguous 2-byte unknown records under the default limit, or an unknown + group with more nested fields than the limit — now fail at view decode with + `UnknownFieldLimitExceeded`. Consumers that converted such views already + got this error at conversion; view-only consumers that re-encoded such + payloads without converting (e.g. a zero-copy passthrough proxy) now see it + at decode — raise the bound with `DecodeOptions::with_unknown_field_limit` + if such payloads are trusted and expected. The accounting lives in the + runtime (`UnknownFieldsView::push_record`), so previously generated code is + fixed without regeneration. (#266) + +[0.8.1]: https://github.com/anthropics/buffa/compare/v0.8.0...v0.8.1 diff --git a/.changes/unreleased/fixed-20260701-041207.yaml b/.changes/unreleased/fixed-20260701-041207.yaml deleted file mode 100644 index 020f3d62..00000000 --- a/.changes/unreleased/fixed-20260701-041207.yaml +++ /dev/null @@ -1,4 +0,0 @@ -kind: Fixed -body: |- - Zero-copy view decoding now charges the unknown-field limit per re-materializable field — one per unknown record plus, for unknown group records, one per nested field — instead of one per coalesced span, and conversion replays under exactly the field budget and group-nesting depth recorded at decode time (previously a fixed recursion limit, which could reject deep unknown groups decoded under a raised `with_recursion_limit`). Decode-time accounting now matches what `to_owned_message` re-materializes, which gives views a guarantee: **a view produced by `decode_view` always converts via `to_owned_message` without error** (the `Result` remains for hand-written impls and `push_raw`-built views). **Behavioral tightening:** payloads whose unknown-field count exceeds the limit but previously slipped through view decode via span coalescing — e.g. a ~2 MiB run of >1M contiguous 2-byte unknown records under the default limit, or an unknown group with more nested fields than the limit — now fail at view decode with `UnknownFieldLimitExceeded`. Consumers that converted such views already got this error at conversion; view-only consumers that re-encoded such payloads without converting (e.g. a zero-copy passthrough proxy) now see it at decode — raise the bound with `DecodeOptions::with_unknown_field_limit` if such payloads are trusted and expected. The accounting lives in the runtime (`UnknownFieldsView::push_record`), so previously generated code is fixed without regeneration. (#266) -time: 2026-07-01T04:12:07.000000000Z diff --git a/CHANGELOG.md b/CHANGELOG.md index 7810be09..deddbd6d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,40 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), Entries for unreleased changes live as fragment files under [`.changes/unreleased/`](.changes/unreleased/); run `task changelog-new` to add one. This file is assembled at release time — do not edit it directly. +## [0.8.1] - 2026-07-01 + +A single-fix patch release: unknown-field limit accounting for zero-copy +views now matches owned conversion exactly, establishing the guarantee that +a view which decodes successfully always converts to an owned message. No +API changes, and regenerating code is not required — the fix lives in the +runtime. + +### Fixed + +- **Zero-copy view decoding now charges the unknown-field limit per + re-materializable field** — one per unknown record plus, for unknown group + records, one per nested field — instead of one per coalesced span, and + conversion replays under exactly the field budget and group-nesting depth + recorded at decode time (previously a fixed recursion limit, which could + reject deep unknown groups decoded under a raised `with_recursion_limit`). + Decode-time accounting now matches what `to_owned_message` re-materializes, + which gives views a guarantee: **a view produced by `decode_view` always + converts via `to_owned_message` without error** (the `Result` remains for + hand-written impls and `push_raw`-built views). **Behavioral tightening:** + payloads whose unknown-field count exceeds the limit but previously slipped + through view decode via span coalescing — e.g. a ~2 MiB run of >1M + contiguous 2-byte unknown records under the default limit, or an unknown + group with more nested fields than the limit — now fail at view decode with + `UnknownFieldLimitExceeded`. Consumers that converted such views already + got this error at conversion; view-only consumers that re-encoded such + payloads without converting (e.g. a zero-copy passthrough proxy) now see it + at decode — raise the bound with `DecodeOptions::with_unknown_field_limit` + if such payloads are trusted and expected. The accounting lives in the + runtime (`UnknownFieldsView::push_record`), so previously generated code is + fixed without regeneration. (#266) + +[0.8.1]: https://github.com/anthropics/buffa/compare/v0.8.0...v0.8.1 + ## [0.8.0] - 2026-06-25 The headline of this release is that the owned representation of every field From c54114650f1eddc2f5162b1cbda7a2fd0c078439 Mon Sep 17 00:00:00 2001 From: Iain McGinniss <309153+iainmcgin@users.noreply.github.com> Date: Wed, 1 Jul 2026 10:10:26 -0700 Subject: [PATCH 2/2] view: make OwnedView::to_owned_message infallible MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Every OwnedView constructor wire-decodes its view (decode, decode_with_options, from_owned), and a view produced by wire decoding always converts — since 0.8.1, decode-time unknown-field accounting charges exactly what conversion re-materializes and conversion replays under the recorded budget and group-nesting depth. The Result on OwnedView::to_owned_message therefore only ever encoded an unreachable error path, which downstream RPC glue was papering over with internal unwraps. Drop it: the method (and the generated FooOwnedView wrapper method) now returns the owned message directly, with #[must_use] preserving the discarded-result lint the implicit Result used to provide. The MessageView trait method deliberately stays fallible: hand-written impls and push_raw-built views can legitimately fail, and plain view types cannot carry wire-decode provenance in their own type. The trait doc now cross-references the infallible OwnedView sibling. A contract violation — a buggy hand-written MessageView impl wrapped in OwnedView, or a from_parts view without wire-decode provenance — panics with a descriptive message via a non-generic #[cold] path (format machinery emitted once, not per monomorphization), pinned by a should_panic test. from_parts' safety contract is strengthened accordingly: the view must have been produced by wire-decoding the buffer, not merely borrow from it. The examples/bsr-quickstart generated code intentionally lags: it is produced by the published BSR plugin (pinned), already does not compile on main against the current runtime, and is regenerated when the next plugin ships. --- .../breaking-changes-20260701-165230.yaml | 4 + buffa-codegen/src/owned_view.rs | 14 +- .../google.protobuf.compiler.plugin.__view.rs | 63 +-- .../google.protobuf.descriptor.__view.rs | 514 ++++++++---------- buffa-test/src/tests/box_type.rs | 6 +- buffa-test/src/tests/inline_field.rs | 3 +- buffa-test/src/tests/map_type.rs | 3 +- buffa-test/src/tests/map_type_custom.rs | 3 +- buffa-test/src/tests/owned_view.rs | 4 +- buffa-test/src/tests/repeated_type.rs | 3 +- buffa-test/tests/string_map.rs | 3 +- buffa-types/src/any_ext.rs | 2 +- .../generated/google.protobuf.any.__view.rs | 14 +- .../google.protobuf.duration.__view.rs | 14 +- .../generated/google.protobuf.empty.__view.rs | 14 +- .../google.protobuf.field_mask.__view.rs | 14 +- .../google.protobuf.struct.__view.rs | 42 +- .../google.protobuf.timestamp.__view.rs | 14 +- .../google.protobuf.wrappers.__view.rs | 126 ++--- buffa/src/view.rs | 100 +++- docs/guide.md | 10 +- docs/migration-from-prost.md | 2 +- 22 files changed, 498 insertions(+), 474 deletions(-) create mode 100644 .changes/unreleased/breaking-changes-20260701-165230.yaml diff --git a/.changes/unreleased/breaking-changes-20260701-165230.yaml b/.changes/unreleased/breaking-changes-20260701-165230.yaml new file mode 100644 index 00000000..6b71bb9c --- /dev/null +++ b/.changes/unreleased/breaking-changes-20260701-165230.yaml @@ -0,0 +1,4 @@ +kind: Breaking changes +body: |- + `OwnedView::to_owned_message` and the generated `FooOwnedView::to_owned_message` are now **infallible**, returning the owned message directly instead of `Result<_, DecodeError>`. Every `OwnedView` constructor wire-decodes its view (or, for `unsafe from_parts`, requires wire-decode provenance as part of its strengthened safety contract), and since 0.8.1 a view produced by wire decoding always converts — so the `Result` only ever encoded an unreachable error path. Migration: on call sites whose receiver is an `OwnedView` or a generated `FooOwnedView` handle, delete the `?` / `.unwrap()` / `.expect(...)` — or otherwise unwrap the previously-returned `Result` (a `match` or `.map_err(...)` needs the same treatment). Call sites on plain view types (`FooView::to_owned_message` via the `MessageView` trait) are unchanged and stay fallible, since hand-written impls and `push_raw`-built views can still legitimately fail. **`unsafe from_parts` callers**: the safety contract now requires that the view was produced by wire-decoding the buffer, not merely that its borrows point into it — a hand-assembled view that was legal under the old wording still compiles but now panics at `to_owned_message`, so audit `from_parts` call sites for provenance. A contract violation by a buggy hand-written `MessageView` impl wrapped in `OwnedView` likewise panics with a descriptive message instead of surfacing an error that correct code could never observe. (#268) +time: 2026-07-01T16:52:30.000000000Z diff --git a/buffa-codegen/src/owned_view.rs b/buffa-codegen/src/owned_view.rs index 2b983a4e..8be495c1 100644 --- a/buffa-codegen/src/owned_view.rs +++ b/buffa-codegen/src/owned_view.rs @@ -283,13 +283,13 @@ pub(crate) fn generate_owned_view_wrapper( /// Convert to the owned message type. /// - /// # Errors - /// - /// Returns an error if re-materializing preserved unknown fields - /// fails (e.g. the unknown-field limit is exceeded). - pub fn to_owned_message( - &self, - ) -> ::core::result::Result<#owned_path, ::buffa::DecodeError> { + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> #owned_path { self.0.to_owned_message() } diff --git a/buffa-descriptor/src/generated/google.protobuf.compiler.plugin.__view.rs b/buffa-descriptor/src/generated/google.protobuf.compiler.plugin.__view.rs index 5deedcf3..dc04a62c 100644 --- a/buffa-descriptor/src/generated/google.protobuf.compiler.plugin.__view.rs +++ b/buffa-descriptor/src/generated/google.protobuf.compiler.plugin.__view.rs @@ -246,13 +246,13 @@ impl VersionOwnedView { } /// Convert to the owned message type. /// - /// # Errors - /// - /// Returns an error if re-materializing preserved unknown fields - /// fails (e.g. the unknown-field limit is exceeded). - pub fn to_owned_message( - &self, - ) -> ::core::result::Result { + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::Version { self.0.to_owned_message() } /// The underlying bytes buffer. @@ -708,16 +708,13 @@ impl CodeGeneratorRequestOwnedView { } /// Convert to the owned message type. /// - /// # Errors - /// - /// Returns an error if re-materializing preserved unknown fields - /// fails (e.g. the unknown-field limit is exceeded). - pub fn to_owned_message( - &self, - ) -> ::core::result::Result< - super::super::CodeGeneratorRequest, - ::buffa::DecodeError, - > { + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::CodeGeneratorRequest { self.0.to_owned_message() } /// The underlying bytes buffer. @@ -1159,16 +1156,13 @@ impl CodeGeneratorResponseOwnedView { } /// Convert to the owned message type. /// - /// # Errors - /// - /// Returns an error if re-materializing preserved unknown fields - /// fails (e.g. the unknown-field limit is exceeded). - pub fn to_owned_message( - &self, - ) -> ::core::result::Result< - super::super::CodeGeneratorResponse, - ::buffa::DecodeError, - > { + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::CodeGeneratorResponse { self.0.to_owned_message() } /// The underlying bytes buffer. @@ -1619,16 +1613,15 @@ pub mod code_generator_response { } /// Convert to the owned message type. /// - /// # Errors - /// - /// Returns an error if re-materializing preserved unknown fields - /// fails (e.g. the unknown-field limit is exceeded). + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] pub fn to_owned_message( &self, - ) -> ::core::result::Result< - super::super::super::code_generator_response::File, - ::buffa::DecodeError, - > { + ) -> super::super::super::code_generator_response::File { self.0.to_owned_message() } /// The underlying bytes buffer. diff --git a/buffa-descriptor/src/generated/google.protobuf.descriptor.__view.rs b/buffa-descriptor/src/generated/google.protobuf.descriptor.__view.rs index 90f9355b..1d9fde9e 100644 --- a/buffa-descriptor/src/generated/google.protobuf.descriptor.__view.rs +++ b/buffa-descriptor/src/generated/google.protobuf.descriptor.__view.rs @@ -214,13 +214,13 @@ impl FileDescriptorSetOwnedView { } /// Convert to the owned message type. /// - /// # Errors - /// - /// Returns an error if re-materializing preserved unknown fields - /// fails (e.g. the unknown-field limit is exceeded). - pub fn to_owned_message( - &self, - ) -> ::core::result::Result { + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::FileDescriptorSet { self.0.to_owned_message() } /// The underlying bytes buffer. @@ -955,16 +955,13 @@ impl FileDescriptorProtoOwnedView { } /// Convert to the owned message type. /// - /// # Errors - /// - /// Returns an error if re-materializing preserved unknown fields - /// fails (e.g. the unknown-field limit is exceeded). - pub fn to_owned_message( - &self, - ) -> ::core::result::Result< - super::super::FileDescriptorProto, - ::buffa::DecodeError, - > { + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::FileDescriptorProto { self.0.to_owned_message() } /// The underlying bytes buffer. @@ -1712,13 +1709,13 @@ impl DescriptorProtoOwnedView { } /// Convert to the owned message type. /// - /// # Errors - /// - /// Returns an error if re-materializing preserved unknown fields - /// fails (e.g. the unknown-field limit is exceeded). - pub fn to_owned_message( - &self, - ) -> ::core::result::Result { + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::DescriptorProto { self.0.to_owned_message() } /// The underlying bytes buffer. @@ -2143,16 +2140,15 @@ pub mod descriptor_proto { } /// Convert to the owned message type. /// - /// # Errors - /// - /// Returns an error if re-materializing preserved unknown fields - /// fails (e.g. the unknown-field limit is exceeded). + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] pub fn to_owned_message( &self, - ) -> ::core::result::Result< - super::super::super::descriptor_proto::ExtensionRange, - ::buffa::DecodeError, - > { + ) -> super::super::super::descriptor_proto::ExtensionRange { self.0.to_owned_message() } /// The underlying bytes buffer. @@ -2443,16 +2439,15 @@ pub mod descriptor_proto { } /// Convert to the owned message type. /// - /// # Errors - /// - /// Returns an error if re-materializing preserved unknown fields - /// fails (e.g. the unknown-field limit is exceeded). + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] pub fn to_owned_message( &self, - ) -> ::core::result::Result< - super::super::super::descriptor_proto::ReservedRange, - ::buffa::DecodeError, - > { + ) -> super::super::super::descriptor_proto::ReservedRange { self.0.to_owned_message() } /// The underlying bytes buffer. @@ -2871,16 +2866,13 @@ impl ExtensionRangeOptionsOwnedView { } /// Convert to the owned message type. /// - /// # Errors - /// - /// Returns an error if re-materializing preserved unknown fields - /// fails (e.g. the unknown-field limit is exceeded). - pub fn to_owned_message( - &self, - ) -> ::core::result::Result< - super::super::ExtensionRangeOptions, - ::buffa::DecodeError, - > { + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::ExtensionRangeOptions { self.0.to_owned_message() } /// The underlying bytes buffer. @@ -3265,16 +3257,15 @@ pub mod extension_range_options { } /// Convert to the owned message type. /// - /// # Errors - /// - /// Returns an error if re-materializing preserved unknown fields - /// fails (e.g. the unknown-field limit is exceeded). + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] pub fn to_owned_message( &self, - ) -> ::core::result::Result< - super::super::super::extension_range_options::Declaration, - ::buffa::DecodeError, - > { + ) -> super::super::super::extension_range_options::Declaration { self.0.to_owned_message() } /// The underlying bytes buffer. @@ -3848,16 +3839,13 @@ impl FieldDescriptorProtoOwnedView { } /// Convert to the owned message type. /// - /// # Errors - /// - /// Returns an error if re-materializing preserved unknown fields - /// fails (e.g. the unknown-field limit is exceeded). - pub fn to_owned_message( - &self, - ) -> ::core::result::Result< - super::super::FieldDescriptorProto, - ::buffa::DecodeError, - > { + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::FieldDescriptorProto { self.0.to_owned_message() } /// The underlying bytes buffer. @@ -4258,16 +4246,13 @@ impl OneofDescriptorProtoOwnedView { } /// Convert to the owned message type. /// - /// # Errors - /// - /// Returns an error if re-materializing preserved unknown fields - /// fails (e.g. the unknown-field limit is exceeded). - pub fn to_owned_message( - &self, - ) -> ::core::result::Result< - super::super::OneofDescriptorProto, - ::buffa::DecodeError, - > { + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::OneofDescriptorProto { self.0.to_owned_message() } /// The underlying bytes buffer. @@ -4712,16 +4697,13 @@ impl EnumDescriptorProtoOwnedView { } /// Convert to the owned message type. /// - /// # Errors - /// - /// Returns an error if re-materializing preserved unknown fields - /// fails (e.g. the unknown-field limit is exceeded). - pub fn to_owned_message( - &self, - ) -> ::core::result::Result< - super::super::EnumDescriptorProto, - ::buffa::DecodeError, - > { + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::EnumDescriptorProto { self.0.to_owned_message() } /// The underlying bytes buffer. @@ -5047,16 +5029,15 @@ pub mod enum_descriptor_proto { } /// Convert to the owned message type. /// - /// # Errors - /// - /// Returns an error if re-materializing preserved unknown fields - /// fails (e.g. the unknown-field limit is exceeded). + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] pub fn to_owned_message( &self, - ) -> ::core::result::Result< - super::super::super::enum_descriptor_proto::EnumReservedRange, - ::buffa::DecodeError, - > { + ) -> super::super::super::enum_descriptor_proto::EnumReservedRange { self.0.to_owned_message() } /// The underlying bytes buffer. @@ -5384,16 +5365,13 @@ impl EnumValueDescriptorProtoOwnedView { } /// Convert to the owned message type. /// - /// # Errors - /// - /// Returns an error if re-materializing preserved unknown fields - /// fails (e.g. the unknown-field limit is exceeded). - pub fn to_owned_message( - &self, - ) -> ::core::result::Result< - super::super::EnumValueDescriptorProto, - ::buffa::DecodeError, - > { + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::EnumValueDescriptorProto { self.0.to_owned_message() } /// The underlying bytes buffer. @@ -5745,16 +5723,13 @@ impl ServiceDescriptorProtoOwnedView { } /// Convert to the owned message type. /// - /// # Errors - /// - /// Returns an error if re-materializing preserved unknown fields - /// fails (e.g. the unknown-field limit is exceeded). - pub fn to_owned_message( - &self, - ) -> ::core::result::Result< - super::super::ServiceDescriptorProto, - ::buffa::DecodeError, - > { + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::ServiceDescriptorProto { self.0.to_owned_message() } /// The underlying bytes buffer. @@ -6154,16 +6129,13 @@ impl MethodDescriptorProtoOwnedView { } /// Convert to the owned message type. /// - /// # Errors - /// - /// Returns an error if re-materializing preserved unknown fields - /// fails (e.g. the unknown-field limit is exceeded). - pub fn to_owned_message( - &self, - ) -> ::core::result::Result< - super::super::MethodDescriptorProto, - ::buffa::DecodeError, - > { + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::MethodDescriptorProto { self.0.to_owned_message() } /// The underlying bytes buffer. @@ -7011,13 +6983,13 @@ impl FileOptionsOwnedView { } /// Convert to the owned message type. /// - /// # Errors - /// - /// Returns an error if re-materializing preserved unknown fields - /// fails (e.g. the unknown-field limit is exceeded). - pub fn to_owned_message( - &self, - ) -> ::core::result::Result { + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::FileOptions { self.0.to_owned_message() } /// The underlying bytes buffer. @@ -7707,13 +7679,13 @@ impl MessageOptionsOwnedView { } /// Convert to the owned message type. /// - /// # Errors - /// - /// Returns an error if re-materializing preserved unknown fields - /// fails (e.g. the unknown-field limit is exceeded). - pub fn to_owned_message( - &self, - ) -> ::core::result::Result { + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::MessageOptions { self.0.to_owned_message() } /// The underlying bytes buffer. @@ -8561,13 +8533,13 @@ impl FieldOptionsOwnedView { } /// Convert to the owned message type. /// - /// # Errors - /// - /// Returns an error if re-materializing preserved unknown fields - /// fails (e.g. the unknown-field limit is exceeded). - pub fn to_owned_message( - &self, - ) -> ::core::result::Result { + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::FieldOptions { self.0.to_owned_message() } /// The underlying bytes buffer. @@ -9008,16 +8980,15 @@ pub mod field_options { } /// Convert to the owned message type. /// - /// # Errors - /// - /// Returns an error if re-materializing preserved unknown fields - /// fails (e.g. the unknown-field limit is exceeded). + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] pub fn to_owned_message( &self, - ) -> ::core::result::Result< - super::super::super::field_options::EditionDefault, - ::buffa::DecodeError, - > { + ) -> super::super::super::field_options::EditionDefault { self.0.to_owned_message() } /// The underlying bytes buffer. @@ -9383,16 +9354,15 @@ pub mod field_options { } /// Convert to the owned message type. /// - /// # Errors - /// - /// Returns an error if re-materializing preserved unknown fields - /// fails (e.g. the unknown-field limit is exceeded). + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] pub fn to_owned_message( &self, - ) -> ::core::result::Result< - super::super::super::field_options::FeatureSupport, - ::buffa::DecodeError, - > { + ) -> super::super::super::field_options::FeatureSupport { self.0.to_owned_message() } /// The underlying bytes buffer. @@ -9747,13 +9717,13 @@ impl OneofOptionsOwnedView { } /// Convert to the owned message type. /// - /// # Errors - /// - /// Returns an error if re-materializing preserved unknown fields - /// fails (e.g. the unknown-field limit is exceeded). - pub fn to_owned_message( - &self, - ) -> ::core::result::Result { + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::OneofOptions { self.0.to_owned_message() } /// The underlying bytes buffer. @@ -10168,13 +10138,13 @@ impl EnumOptionsOwnedView { } /// Convert to the owned message type. /// - /// # Errors - /// - /// Returns an error if re-materializing preserved unknown fields - /// fails (e.g. the unknown-field limit is exceeded). - pub fn to_owned_message( - &self, - ) -> ::core::result::Result { + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::EnumOptions { self.0.to_owned_message() } /// The underlying bytes buffer. @@ -10646,13 +10616,13 @@ impl EnumValueOptionsOwnedView { } /// Convert to the owned message type. /// - /// # Errors - /// - /// Returns an error if re-materializing preserved unknown fields - /// fails (e.g. the unknown-field limit is exceeded). - pub fn to_owned_message( - &self, - ) -> ::core::result::Result { + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::EnumValueOptions { self.0.to_owned_message() } /// The underlying bytes buffer. @@ -11051,13 +11021,13 @@ impl ServiceOptionsOwnedView { } /// Convert to the owned message type. /// - /// # Errors - /// - /// Returns an error if re-materializing preserved unknown fields - /// fails (e.g. the unknown-field limit is exceeded). - pub fn to_owned_message( - &self, - ) -> ::core::result::Result { + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::ServiceOptions { self.0.to_owned_message() } /// The underlying bytes buffer. @@ -11473,13 +11443,13 @@ impl MethodOptionsOwnedView { } /// Convert to the owned message type. /// - /// # Errors - /// - /// Returns an error if re-materializing preserved unknown fields - /// fails (e.g. the unknown-field limit is exceeded). - pub fn to_owned_message( - &self, - ) -> ::core::result::Result { + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::MethodOptions { self.0.to_owned_message() } /// The underlying bytes buffer. @@ -11923,16 +11893,13 @@ impl UninterpretedOptionOwnedView { } /// Convert to the owned message type. /// - /// # Errors - /// - /// Returns an error if re-materializing preserved unknown fields - /// fails (e.g. the unknown-field limit is exceeded). - pub fn to_owned_message( - &self, - ) -> ::core::result::Result< - super::super::UninterpretedOption, - ::buffa::DecodeError, - > { + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::UninterpretedOption { self.0.to_owned_message() } /// The underlying bytes buffer. @@ -12255,16 +12222,15 @@ Distinguishes a field that was absent from one explicitly encoded with its defau } /// Convert to the owned message type. /// - /// # Errors - /// - /// Returns an error if re-materializing preserved unknown fields - /// fails (e.g. the unknown-field limit is exceeded). + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] pub fn to_owned_message( &self, - ) -> ::core::result::Result< - super::super::super::uninterpreted_option::NamePart, - ::buffa::DecodeError, - > { + ) -> super::super::super::uninterpreted_option::NamePart { self.0.to_owned_message() } /// The underlying bytes buffer. @@ -12763,13 +12729,13 @@ impl FeatureSetOwnedView { } /// Convert to the owned message type. /// - /// # Errors - /// - /// Returns an error if re-materializing preserved unknown fields - /// fails (e.g. the unknown-field limit is exceeded). - pub fn to_owned_message( - &self, - ) -> ::core::result::Result { + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::FeatureSet { self.0.to_owned_message() } /// The underlying bytes buffer. @@ -13054,16 +13020,15 @@ pub mod feature_set { } /// Convert to the owned message type. /// - /// # Errors - /// - /// Returns an error if re-materializing preserved unknown fields - /// fails (e.g. the unknown-field limit is exceeded). + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] pub fn to_owned_message( &self, - ) -> ::core::result::Result< - super::super::super::feature_set::VisibilityFeature, - ::buffa::DecodeError, - > { + ) -> super::super::super::feature_set::VisibilityFeature { self.0.to_owned_message() } /// The underlying bytes buffer. @@ -13397,13 +13362,13 @@ impl FeatureSetDefaultsOwnedView { } /// Convert to the owned message type. /// - /// # Errors - /// - /// Returns an error if re-materializing preserved unknown fields - /// fails (e.g. the unknown-field limit is exceeded). - pub fn to_owned_message( - &self, - ) -> ::core::result::Result { + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::FeatureSetDefaults { self.0.to_owned_message() } /// The underlying bytes buffer. @@ -13822,16 +13787,15 @@ pub mod feature_set_defaults { } /// Convert to the owned message type. /// - /// # Errors - /// - /// Returns an error if re-materializing preserved unknown fields - /// fails (e.g. the unknown-field limit is exceeded). + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] pub fn to_owned_message( &self, - ) -> ::core::result::Result< - super::super::super::feature_set_defaults::FeatureSetEditionDefault, - ::buffa::DecodeError, - > { + ) -> super::super::super::feature_set_defaults::FeatureSetEditionDefault { self.0.to_owned_message() } /// The underlying bytes buffer. @@ -14168,13 +14132,13 @@ impl SourceCodeInfoOwnedView { } /// Convert to the owned message type. /// - /// # Errors - /// - /// Returns an error if re-materializing preserved unknown fields - /// fails (e.g. the unknown-field limit is exceeded). - pub fn to_owned_message( - &self, - ) -> ::core::result::Result { + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::SourceCodeInfo { self.0.to_owned_message() } /// The underlying bytes buffer. @@ -14705,16 +14669,15 @@ pub mod source_code_info { } /// Convert to the owned message type. /// - /// # Errors - /// - /// Returns an error if re-materializing preserved unknown fields - /// fails (e.g. the unknown-field limit is exceeded). + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] pub fn to_owned_message( &self, - ) -> ::core::result::Result< - super::super::super::source_code_info::Location, - ::buffa::DecodeError, - > { + ) -> super::super::super::source_code_info::Location { self.0.to_owned_message() } /// The underlying bytes buffer. @@ -15086,13 +15049,13 @@ impl GeneratedCodeInfoOwnedView { } /// Convert to the owned message type. /// - /// # Errors - /// - /// Returns an error if re-materializing preserved unknown fields - /// fails (e.g. the unknown-field limit is exceeded). - pub fn to_owned_message( - &self, - ) -> ::core::result::Result { + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::GeneratedCodeInfo { self.0.to_owned_message() } /// The underlying bytes buffer. @@ -15484,16 +15447,15 @@ pub mod generated_code_info { } /// Convert to the owned message type. /// - /// # Errors - /// - /// Returns an error if re-materializing preserved unknown fields - /// fails (e.g. the unknown-field limit is exceeded). + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] pub fn to_owned_message( &self, - ) -> ::core::result::Result< - super::super::super::generated_code_info::Annotation, - ::buffa::DecodeError, - > { + ) -> super::super::super::generated_code_info::Annotation { self.0.to_owned_message() } /// The underlying bytes buffer. diff --git a/buffa-test/src/tests/box_type.rs b/buffa-test/src/tests/box_type.rs index 81f298db..3f4b8c5e 100644 --- a/buffa-test/src/tests/box_type.rs +++ b/buffa-test/src/tests/box_type.rs @@ -86,8 +86,7 @@ fn view_to_owned_round_trip() { let bytes = bytes::Bytes::from(sample().encode_to_vec()); let owned: Outer = crate::box_type::OuterOwnedView::decode(bytes) .expect("decode view") - .to_owned_message() - .expect("to_owned"); + .to_owned_message(); assert_eq!(owned, sample()); } @@ -145,7 +144,6 @@ fn oneof_view_to_owned_round_trip() { let bytes = bytes::Bytes::from(msg.encode_to_vec()); let owned: WithOneof = crate::box_type::WithOneofOwnedView::decode(bytes) .expect("decode view") - .to_owned_message() - .expect("to_owned"); + .to_owned_message(); assert_eq!(owned, msg); } diff --git a/buffa-test/src/tests/inline_field.rs b/buffa-test/src/tests/inline_field.rs index 7f3e4454..c6c2581e 100644 --- a/buffa-test/src/tests/inline_field.rs +++ b/buffa-test/src/tests/inline_field.rs @@ -83,7 +83,6 @@ fn view_to_owned_round_trip() { let bytes = bytes::Bytes::from(sample().encode_to_vec()); let owned: Outer = crate::inline_field::OuterOwnedView::decode(bytes) .expect("decode view") - .to_owned_message() - .expect("to_owned"); + .to_owned_message(); assert_eq!(owned, sample()); } diff --git a/buffa-test/src/tests/map_type.rs b/buffa-test/src/tests/map_type.rs index ec4de47d..b041f4e5 100644 --- a/buffa-test/src/tests/map_type.rs +++ b/buffa-test/src/tests/map_type.rs @@ -118,8 +118,7 @@ fn view_to_owned_round_trip() { let bytes = bytes::Bytes::from(sample().encode_to_vec()); let owned: Maps = crate::map_type::MapsOwnedView::decode(bytes) .expect("decode view") - .to_owned_message() - .expect("to_owned"); + .to_owned_message(); assert_eq!(owned, sample()); } diff --git a/buffa-test/src/tests/map_type_custom.rs b/buffa-test/src/tests/map_type_custom.rs index 65ff189b..8f77775a 100644 --- a/buffa-test/src/tests/map_type_custom.rs +++ b/buffa-test/src/tests/map_type_custom.rs @@ -81,7 +81,6 @@ fn view_to_owned_round_trip() { let bytes = bytes::Bytes::from(sample().encode_to_vec()); let owned: CustomMaps = crate::map_type_custom::CustomMapsOwnedView::decode(bytes) .expect("decode view") - .to_owned_message() - .expect("to_owned"); + .to_owned_message(); assert_eq!(owned, sample()); } diff --git a/buffa-test/src/tests/owned_view.rs b/buffa-test/src/tests/owned_view.rs index 9edb6ee0..252c3873 100644 --- a/buffa-test/src/tests/owned_view.rs +++ b/buffa-test/src/tests/owned_view.rs @@ -55,7 +55,7 @@ fn test_owned_view_wrapper_view_escape_hatch() { fn test_owned_view_wrapper_owned_roundtrip() { let msg = sample_person(); let owned = PersonOwnedView::from_owned(&msg).expect("from_owned"); - let back: Person = owned.to_owned_message().unwrap(); + let back: Person = owned.to_owned_message(); assert_eq!(back, msg); } @@ -183,7 +183,7 @@ mod view_family { let raw = handle.as_ref(); let _view = raw.reborrow(); let len = raw.bytes().len(); - (raw.to_owned_message().unwrap(), len) + (raw.to_owned_message(), len) } #[test] diff --git a/buffa-test/src/tests/repeated_type.rs b/buffa-test/src/tests/repeated_type.rs index 5e2f8827..5799d1e2 100644 --- a/buffa-test/src/tests/repeated_type.rs +++ b/buffa-test/src/tests/repeated_type.rs @@ -73,7 +73,6 @@ fn view_to_owned_round_trip() { let bytes = bytes::Bytes::from(sample().encode_to_vec()); let owned: Lists = crate::repeated_type::ListsOwnedView::decode(bytes) .expect("decode view") - .to_owned_message() - .expect("to_owned"); + .to_owned_message(); assert_eq!(owned, sample()); } diff --git a/buffa-test/tests/string_map.rs b/buffa-test/tests/string_map.rs index 92c60dd3..4f12d80d 100644 --- a/buffa-test/tests/string_map.rs +++ b/buffa-test/tests/string_map.rs @@ -117,8 +117,7 @@ fn view_to_owned_round_trip() { let bytes = bytes::Bytes::from(sample().encode_to_vec()); let owned: Maps = buffa_test::string_map::MapsOwnedView::decode(bytes) .expect("decode view") - .to_owned_message() - .expect("to_owned"); + .to_owned_message(); assert_eq!(owned, sample()); } diff --git a/buffa-types/src/any_ext.rs b/buffa-types/src/any_ext.rs index 724959f6..98e4cd07 100644 --- a/buffa-types/src/any_ext.rs +++ b/buffa-types/src/any_ext.rs @@ -376,7 +376,7 @@ mod tests { // through to_owned_from_source(Some(&self.bytes)), so the bytes field // is a zero-copy slice_ref into the retained buffer. let ov = OwnedView::>::decode(buf.clone()).unwrap(); - let owned2 = ov.to_owned_message().unwrap(); + let owned2 = ov.to_owned_message(); assert_eq!(owned2.value, src.value); assert!(buf_range.contains(&(owned2.value.as_ptr() as usize))); diff --git a/buffa-types/src/generated/google.protobuf.any.__view.rs b/buffa-types/src/generated/google.protobuf.any.__view.rs index 11738529..77fd6412 100644 --- a/buffa-types/src/generated/google.protobuf.any.__view.rs +++ b/buffa-types/src/generated/google.protobuf.any.__view.rs @@ -302,13 +302,13 @@ impl AnyOwnedView { } /// Convert to the owned message type. /// - /// # Errors - /// - /// Returns an error if re-materializing preserved unknown fields - /// fails (e.g. the unknown-field limit is exceeded). - pub fn to_owned_message( - &self, - ) -> ::core::result::Result { + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::Any { self.0.to_owned_message() } /// The underlying bytes buffer. diff --git a/buffa-types/src/generated/google.protobuf.duration.__view.rs b/buffa-types/src/generated/google.protobuf.duration.__view.rs index e6588216..ff22a398 100644 --- a/buffa-types/src/generated/google.protobuf.duration.__view.rs +++ b/buffa-types/src/generated/google.protobuf.duration.__view.rs @@ -251,13 +251,13 @@ impl DurationOwnedView { } /// Convert to the owned message type. /// - /// # Errors - /// - /// Returns an error if re-materializing preserved unknown fields - /// fails (e.g. the unknown-field limit is exceeded). - pub fn to_owned_message( - &self, - ) -> ::core::result::Result { + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::Duration { self.0.to_owned_message() } /// The underlying bytes buffer. diff --git a/buffa-types/src/generated/google.protobuf.empty.__view.rs b/buffa-types/src/generated/google.protobuf.empty.__view.rs index 704561b3..4b403f82 100644 --- a/buffa-types/src/generated/google.protobuf.empty.__view.rs +++ b/buffa-types/src/generated/google.protobuf.empty.__view.rs @@ -151,13 +151,13 @@ impl EmptyOwnedView { } /// Convert to the owned message type. /// - /// # Errors - /// - /// Returns an error if re-materializing preserved unknown fields - /// fails (e.g. the unknown-field limit is exceeded). - pub fn to_owned_message( - &self, - ) -> ::core::result::Result { + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::Empty { self.0.to_owned_message() } /// The underlying bytes buffer. diff --git a/buffa-types/src/generated/google.protobuf.field_mask.__view.rs b/buffa-types/src/generated/google.protobuf.field_mask.__view.rs index 31741ba8..7d16655e 100644 --- a/buffa-types/src/generated/google.protobuf.field_mask.__view.rs +++ b/buffa-types/src/generated/google.protobuf.field_mask.__view.rs @@ -387,13 +387,13 @@ impl FieldMaskOwnedView { } /// Convert to the owned message type. /// - /// # Errors - /// - /// Returns an error if re-materializing preserved unknown fields - /// fails (e.g. the unknown-field limit is exceeded). - pub fn to_owned_message( - &self, - ) -> ::core::result::Result { + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::FieldMask { self.0.to_owned_message() } /// The underlying bytes buffer. diff --git a/buffa-types/src/generated/google.protobuf.struct.__view.rs b/buffa-types/src/generated/google.protobuf.struct.__view.rs index f416bcbf..beddae53 100644 --- a/buffa-types/src/generated/google.protobuf.struct.__view.rs +++ b/buffa-types/src/generated/google.protobuf.struct.__view.rs @@ -249,13 +249,13 @@ impl StructOwnedView { } /// Convert to the owned message type. /// - /// # Errors - /// - /// Returns an error if re-materializing preserved unknown fields - /// fails (e.g. the unknown-field limit is exceeded). - pub fn to_owned_message( - &self, - ) -> ::core::result::Result { + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::Struct { self.0.to_owned_message() } /// The underlying bytes buffer. @@ -753,13 +753,13 @@ impl ValueOwnedView { } /// Convert to the owned message type. /// - /// # Errors - /// - /// Returns an error if re-materializing preserved unknown fields - /// fails (e.g. the unknown-field limit is exceeded). - pub fn to_owned_message( - &self, - ) -> ::core::result::Result { + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::Value { self.0.to_owned_message() } /// The underlying bytes buffer. @@ -1187,13 +1187,13 @@ impl ListValueOwnedView { } /// Convert to the owned message type. /// - /// # Errors - /// - /// Returns an error if re-materializing preserved unknown fields - /// fails (e.g. the unknown-field limit is exceeded). - pub fn to_owned_message( - &self, - ) -> ::core::result::Result { + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::ListValue { self.0.to_owned_message() } /// The underlying bytes buffer. diff --git a/buffa-types/src/generated/google.protobuf.timestamp.__view.rs b/buffa-types/src/generated/google.protobuf.timestamp.__view.rs index dbbc94a6..d42db5af 100644 --- a/buffa-types/src/generated/google.protobuf.timestamp.__view.rs +++ b/buffa-types/src/generated/google.protobuf.timestamp.__view.rs @@ -288,13 +288,13 @@ impl TimestampOwnedView { } /// Convert to the owned message type. /// - /// # Errors - /// - /// Returns an error if re-materializing preserved unknown fields - /// fails (e.g. the unknown-field limit is exceeded). - pub fn to_owned_message( - &self, - ) -> ::core::result::Result { + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::Timestamp { self.0.to_owned_message() } /// The underlying bytes buffer. diff --git a/buffa-types/src/generated/google.protobuf.wrappers.__view.rs b/buffa-types/src/generated/google.protobuf.wrappers.__view.rs index 88ebff4d..292bef2e 100644 --- a/buffa-types/src/generated/google.protobuf.wrappers.__view.rs +++ b/buffa-types/src/generated/google.protobuf.wrappers.__view.rs @@ -167,13 +167,13 @@ impl DoubleValueOwnedView { } /// Convert to the owned message type. /// - /// # Errors - /// - /// Returns an error if re-materializing preserved unknown fields - /// fails (e.g. the unknown-field limit is exceeded). - pub fn to_owned_message( - &self, - ) -> ::core::result::Result { + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::DoubleValue { self.0.to_owned_message() } /// The underlying bytes buffer. @@ -472,13 +472,13 @@ impl FloatValueOwnedView { } /// Convert to the owned message type. /// - /// # Errors - /// - /// Returns an error if re-materializing preserved unknown fields - /// fails (e.g. the unknown-field limit is exceeded). - pub fn to_owned_message( - &self, - ) -> ::core::result::Result { + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::FloatValue { self.0.to_owned_message() } /// The underlying bytes buffer. @@ -777,13 +777,13 @@ impl Int64ValueOwnedView { } /// Convert to the owned message type. /// - /// # Errors - /// - /// Returns an error if re-materializing preserved unknown fields - /// fails (e.g. the unknown-field limit is exceeded). - pub fn to_owned_message( - &self, - ) -> ::core::result::Result { + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::Int64Value { self.0.to_owned_message() } /// The underlying bytes buffer. @@ -1082,13 +1082,13 @@ impl UInt64ValueOwnedView { } /// Convert to the owned message type. /// - /// # Errors - /// - /// Returns an error if re-materializing preserved unknown fields - /// fails (e.g. the unknown-field limit is exceeded). - pub fn to_owned_message( - &self, - ) -> ::core::result::Result { + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::UInt64Value { self.0.to_owned_message() } /// The underlying bytes buffer. @@ -1387,13 +1387,13 @@ impl Int32ValueOwnedView { } /// Convert to the owned message type. /// - /// # Errors - /// - /// Returns an error if re-materializing preserved unknown fields - /// fails (e.g. the unknown-field limit is exceeded). - pub fn to_owned_message( - &self, - ) -> ::core::result::Result { + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::Int32Value { self.0.to_owned_message() } /// The underlying bytes buffer. @@ -1692,13 +1692,13 @@ impl UInt32ValueOwnedView { } /// Convert to the owned message type. /// - /// # Errors - /// - /// Returns an error if re-materializing preserved unknown fields - /// fails (e.g. the unknown-field limit is exceeded). - pub fn to_owned_message( - &self, - ) -> ::core::result::Result { + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::UInt32Value { self.0.to_owned_message() } /// The underlying bytes buffer. @@ -1997,13 +1997,13 @@ impl BoolValueOwnedView { } /// Convert to the owned message type. /// - /// # Errors - /// - /// Returns an error if re-materializing preserved unknown fields - /// fails (e.g. the unknown-field limit is exceeded). - pub fn to_owned_message( - &self, - ) -> ::core::result::Result { + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::BoolValue { self.0.to_owned_message() } /// The underlying bytes buffer. @@ -2302,13 +2302,13 @@ impl StringValueOwnedView { } /// Convert to the owned message type. /// - /// # Errors - /// - /// Returns an error if re-materializing preserved unknown fields - /// fails (e.g. the unknown-field limit is exceeded). - pub fn to_owned_message( - &self, - ) -> ::core::result::Result { + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::StringValue { self.0.to_owned_message() } /// The underlying bytes buffer. @@ -2607,13 +2607,13 @@ impl BytesValueOwnedView { } /// Convert to the owned message type. /// - /// # Errors - /// - /// Returns an error if re-materializing preserved unknown fields - /// fails (e.g. the unknown-field limit is exceeded). - pub fn to_owned_message( - &self, - ) -> ::core::result::Result { + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::BytesValue { self.0.to_owned_message() } /// The underlying bytes buffer. diff --git a/buffa/src/view.rs b/buffa/src/view.rs index fae3e609..2db653ab 100644 --- a/buffa/src/view.rs +++ b/buffa/src/view.rs @@ -307,6 +307,10 @@ pub trait MessageView<'a>: Sized { /// budget and group-nesting depth recorded at decode time. The `Result` /// remains for hand-written view impls and for views holding manually /// pushed ([`UnknownFieldsView::push_raw`]) unknown-field spans. + /// [`OwnedView`], which always holds a wire-decoded view, exposes this + /// conversion infallibly — see + /// [`OwnedView::to_owned_message`](OwnedView::to_owned_message) (and the + /// generated `FooOwnedView` wrappers likewise). /// /// # Errors /// @@ -1934,8 +1938,9 @@ impl<'a> UnknownFieldsView<'a> { /// println!("name: {}", person.name); /// println!("id: {}", person.id); /// -/// // Convert to owned if you need to store or mutate -/// let owned: Person = view.to_owned_message()?; +/// // Convert to owned if you need to store or mutate — infallible, since +/// // an OwnedView always holds a wire-decoded view. +/// let owned: Person = view.to_owned_message(); /// ``` /// /// Generated code additionally provides a per-message `FooOwnedView` wrapper @@ -2029,6 +2034,18 @@ impl Drop for OwnedView { } } +/// Panic path for [`OwnedView::to_owned_message`], hoisted out of the +/// generic method so the format machinery is emitted once rather than per +/// monomorphization — the branch is unreachable for generated view types. +#[cold] +#[inline(never)] +fn convert_contract_violated(e: DecodeError) -> ! { + panic!( + "OwnedView conversion failed ({e:?}): the wrapped MessageView \ + impl violates the wire-decode => convert contract" + ) +} + impl OwnedView where V: MessageView<'static>, @@ -2104,12 +2121,25 @@ where /// into the retained buffer (zero-copy); other borrowed fields are /// allocated and copied. /// - /// # Errors + /// Infallible: every `OwnedView` constructor wire-decodes its view + /// ([`decode`](Self::decode), [`decode_with_options`](Self::decode_with_options), + /// [`from_owned`](Self::from_owned)) or requires wire-decode provenance + /// as part of its safety contract ([`from_parts`](Self::from_parts)), + /// and a view produced by wire decoding always converts (see + /// [`MessageView::to_owned_message`]). /// - /// Returns an error if re-materializing preserved unknown fields fails - /// (see [`MessageView::to_owned_message`]). - pub fn to_owned_message(&self) -> Result { - self.view.to_owned_from_source(Some(&self.bytes)) + /// # Panics + /// + /// Panics if `V`'s [`MessageView`] implementation violates the + /// wire-decode ⇒ convert contract. Generated view types cannot trigger + /// this; only a buggy hand-written impl (or a + /// [`from_parts`](Self::from_parts) view that breaches its safety + /// contract) can. + #[must_use] + pub fn to_owned_message(&self) -> V::Owned { + self.view + .to_owned_from_source(Some(&self.bytes)) + .unwrap_or_else(|e| convert_contract_violated(e)) } /// Get a reference to the underlying bytes buffer. @@ -2124,10 +2154,15 @@ where /// /// # Safety /// - /// The caller must ensure that **all** borrows in `view` point into the - /// data region of `bytes`. In practice, `view` must have been decoded - /// from `bytes` (or a sub-slice that `bytes` fully contains). Violating - /// this invariant causes undefined behavior (dangling references). + /// The caller must ensure that `view` was produced by **wire-decoding** + /// `bytes` (or a sub-slice that `bytes` fully contains) — e.g. via + /// [`MessageView::decode_view`]. This guarantees both that all borrows + /// in `view` point into the data region of `bytes` (violating that + /// causes undefined behavior — dangling references) and that + /// [`to_owned_message`](Self::to_owned_message)'s infallible-conversion + /// contract holds (a manually assembled view merely borrowing from + /// `bytes` satisfies the borrow requirement but can make conversion + /// panic). pub unsafe fn from_parts(bytes: Bytes, view: V) -> Self { Self { view: core::mem::ManuallyDrop::new(view), @@ -2674,8 +2709,8 @@ mod tests { fn to_owned_of_manual_flood_over_default_limit_fails() { // The replay limit stays live for manually built views: push_raw // spans get the default allowance, no more — the memory- - // amplification bound survives even though wire-decoded views can - // no longer hit it. + // amplification bound survives even though wire-decoded views + // cannot hit it (decode charges the allowance up front). let n = crate::DEFAULT_UNKNOWN_FIELD_LIMIT + 1; let mut buf = alloc::vec::Vec::with_capacity(2 * n); for _ in 0..n { @@ -3127,12 +3162,47 @@ mod tests { fn owned_view_to_owned_message() { let bytes = encode_simple(7, "world"); let view = OwnedView::>::decode(bytes).unwrap(); - let owned = view.to_owned_message().unwrap(); + let owned = view.to_owned_message(); assert_eq!(owned.id, 7); assert_eq!(owned.name, "world"); } + /// A view whose `to_owned_message` breaks the wire-decode ⇒ convert + /// contract, standing in for a buggy hand-written impl. + #[derive(Clone, Debug, Default, PartialEq)] + struct ContractBreakingView<'a>(core::marker::PhantomData<&'a ()>); + + crate::impl_view_reborrow!(ContractBreakingView); + + impl<'a> MessageView<'a> for ContractBreakingView<'a> { + type Owned = SimpleMessage; + fn merge_view_field( + &mut self, + _tag: crate::encoding::Tag, + cur: &'a [u8], + _before_tag: &'a [u8], + _ctx: crate::DecodeContext<'_>, + ) -> Result<&'a [u8], DecodeError> { + Ok(cur) + } + fn decode_view(_buf: &'a [u8]) -> Result { + Ok(Self(core::marker::PhantomData)) + } + fn to_owned_message(&self) -> Result { + Err(DecodeError::UnknownFieldLimitExceeded) + } + } + + #[test] + #[should_panic(expected = "wire-decode => convert contract")] + fn owned_view_panics_when_impl_breaks_convert_contract() { + // The infallible signature rests on the decode ⇒ convert invariant; + // an impl that violates it must fail loudly, not silently. + let view = OwnedView::>::decode(Bytes::new()).unwrap(); + let _ = view.to_owned_message(); + } + #[test] fn owned_view_debug_delegates_to_view() { let bytes = encode_simple(1, "test"); @@ -3193,7 +3263,7 @@ mod tests { assert_eq!(view.reborrow().id, 99); assert_eq!(view.reborrow().name, "roundtrip"); - let back = view.to_owned_message().unwrap(); + let back = view.to_owned_message(); assert_eq!(back, msg); } diff --git a/docs/guide.md b/docs/guide.md index c5754abe..e45619a3 100644 --- a/docs/guide.md +++ b/docs/guide.md @@ -1033,8 +1033,9 @@ let view = PersonView::decode_view(&bytes)?; println!("name: {}", view.name); // &str, no allocation // Convert to owned when needed (e.g., for storage or mutation). -// Infallible for views produced by decode_view; the Result covers -// hand-written view impls. +// Won't error for views from decode_view, but the signature stays +// Result because hand-written view impls can fail; the OwnedView +// handle below drops the Result entirely. let owned: Person = view.to_owned_message()?; ``` @@ -1123,8 +1124,9 @@ println!("id: {}", view.id()); let person = view.view(); for tag in person.tags.iter() { /* ... */ } -// Convert to owned if needed for storage or mutation -let owned: Person = view.to_owned_message()?; +// Convert to owned if needed for storage or mutation — infallible, since +// the handle always holds a wire-decoded view +let owned: Person = view.to_owned_message(); ``` When working with the generic `OwnedView` directly (for example, a request type handed to you by an RPC framework), reach the inner view with `reborrow()`, which ties the borrow to the `OwnedView` itself: `let person = view.reborrow();` then `person.name`. Field access directly on the handle is deliberately not provided — the stored view's lifetime is a synthetic `'static`, and exposing it would let field borrows outlive the buffer they point into. diff --git a/docs/migration-from-prost.md b/docs/migration-from-prost.md index d1d8d34f..3d35dbb8 100644 --- a/docs/migration-from-prost.md +++ b/docs/migration-from-prost.md @@ -251,7 +251,7 @@ use my_crate::pkg::__buffa::view::PersonView; let view = PersonView::decode_view(&bytes)?; println!("name: {}", view.name); // &str, no allocation -let owned: Person = view.to_owned_message(); +let owned: Person = view.to_owned_message()?; ``` ### `OwnedView` for async/RPC use