diff --git a/CHANGELOG.md b/CHANGELOG.md index 7b0d2d59..e7b51c29 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,55 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), ### Added +- **Zero-copy views enforce the unknown-field limit and coalesce adjacent + unknown records.** View decoding previously stored one borrowed span (16 + bytes) per unknown wire record with no bound beyond the input size. Spans + for adjacent unknown records now coalesce into a single span — a + contiguous run of unknown fields costs one `Vec` slot regardless of field + count, and re-encodes byte-identically — and each *new* span (one per + unknown run) is counted against the same unknown-field limit that bounds + owned-message decoding, configured via + `DecodeOptions::with_unknown_field_limit` and honored by + `DecodeOptions::decode_view`. As part of this, the view decode path now + threads `DecodeContext<'_>`: `MessageView::decode_view_with_limit(buf, + depth)` is replaced by `decode_view_with_ctx(buf, ctx)`, and generated + views' hidden `_decode_depth` helpers become `_decode_ctx` (**breaking** + for code generated by earlier releases, which must be regenerated — + consistent with the owned-path change below). + +- **View-to-owned conversion is now fallible and honors the decode-time + limit.** `MessageView::to_owned_message` and `to_owned_from_source` (and + the `OwnedView` wrapper) now return `Result` + (**breaking**): generated conversions previously swallowed unknown-field + re-materialization errors via `unwrap_or_default()`, silently dropping + every unknown field. `UnknownFieldsView::to_owned` also now re-materializes + under the unknown-field allowance that remained when the view recorded its + first unknown field — so a tight `with_unknown_field_limit` configured at + `decode_view` time carries through conversion, where each owned + `UnknownField` counts individually (unlike the coalesced spans the view + stores). Views built manually via `push_raw` fall back to the default + limit. + +- **Unknown-field decode limit bounds decoder memory amplification.** + Unknown wire data can occupy ~20× more memory decoded than encoded: + every 2-byte unknown varint field materializes a ~40-byte + `UnknownField`, so a 64 MiB payload of minimal unknown fields (flat or + nested in a group) could force over 1 GiB of heap — not bounded by + `with_max_message_size`, which only caps input length. Decoding now + counts every materialized unknown field against a limit shared across + the whole decode call and fails with the new + `DecodeError::UnknownFieldLimitExceeded` when it is exceeded. The + default is 1,000,000 fields per decode (`DEFAULT_UNKNOWN_FIELD_LIMIT`), + capping slot overhead at ~40 MB, and applies to all decode entry points + including the trait-level convenience methods; tune it with + `DecodeOptions::with_unknown_field_limit`. Unknown length-delimited + payload bytes are not counted against the limit — the decoder only + allocates them once the sender has actually delivered the bytes, so + they are bounded by the input size and governed by + `with_max_message_size`. The limit covers owned-message and + `DynamicMessage` decoding; zero-copy views store unknown fields as + borrowed spans and are not affected by the amplification. + - **`chrono` interop for `buffa-types`** (#163). A new off-by-default, `no_std`-compatible `chrono` feature adds conversions between the well-known `Timestamp` / `Duration` types and `chrono::DateTime` / @@ -29,6 +78,17 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), carrier-agnostic `Location { line, column }`. Requires message types generated with `json = true`. Contributed by @rsd-darshan. +### Changed + +- **Breaking:** the decode-path `Message` trait methods (`merge`, + `merge_field`, `merge_to_limit`, `merge_group`, `merge_length_delimited`), + `encoding::decode_unknown_field`, and `message_set::merge_item` now take a + `DecodeContext<'_>` — carrying the remaining recursion depth and the + shared unknown-field allowance — in place of the bare `depth: u32`. Code + generated with earlier releases must be regenerated. Callers of the + convenience methods (`decode`, `decode_from_slice`, `merge_from_slice`, + `DecodeOptions`) are unaffected. + ### Fixed - **`DecodeOptions::decode_length_delimited_reader` no longer allocates the diff --git a/DESIGN.md b/DESIGN.md index fbe38cf6..cfe72b3c 100644 --- a/DESIGN.md +++ b/DESIGN.md @@ -372,7 +372,7 @@ pub trait Message: DefaultInstance + Clone + PartialEq + Send + Sync { // Required methods (implemented by codegen per message type): fn compute_size(&self, cache: &mut SizeCache) -> u32; // Pass 1 fn write_to(&self, cache: &mut SizeCache, buf: &mut impl BufMut); // Pass 2 - fn merge_field(&mut self, tag: Tag, buf: &mut impl Buf, depth: u32) + fn merge_field(&mut self, tag: Tag, buf: &mut impl Buf, ctx: DecodeContext<'_>) -> Result<(), DecodeError>; // Per-field decode dispatch fn clear(&mut self); @@ -381,7 +381,7 @@ pub trait Message: DefaultInstance + Clone + PartialEq + Send + Sync { fn encode_to_vec(&self) -> Vec; fn encode_to_bytes(&self) -> Bytes; fn decode_from_slice(data: &[u8]) -> Result; - fn merge(&mut self, buf: &mut impl Buf, depth: u32) -> Result<(), DecodeError>; + fn merge(&mut self, buf: &mut impl Buf, ctx: DecodeContext<'_>) -> Result<(), DecodeError>; fn merge_from_slice(&mut self, data: &[u8]) -> Result<(), DecodeError>; // ... + length-delimited and io::Read variants } diff --git a/buffa-codegen/src/impl_message.rs b/buffa-codegen/src/impl_message.rs index e10719d5..8f44ec34 100644 --- a/buffa-codegen/src/impl_message.rs +++ b/buffa-codegen/src/impl_message.rs @@ -524,19 +524,15 @@ pub fn generate_message_impl( if tag.field_number() == 1 && tag.wire_type() == ::buffa::encoding::WireType::StartGroup { - if depth == 0 { - return ::core::result::Result::Err( - ::buffa::DecodeError::RecursionLimitExceeded, - ); - } - let (type_id, bytes) = ::buffa::message_set::merge_item(buf, depth - 1)?; + let (type_id, bytes) = + ::buffa::message_set::merge_item(buf, ctx.descend()?)?; self.__buffa_unknown_fields.push(::buffa::UnknownField { number: type_id, data: ::buffa::UnknownFieldData::LengthDelimited(bytes), }); } else { self.__buffa_unknown_fields.push( - ::buffa::encoding::decode_unknown_field(tag, buf, depth)? + ::buffa::encoding::decode_unknown_field(tag, buf, ctx)? ); } } @@ -545,13 +541,13 @@ pub fn generate_message_impl( quote! { _ => { self.__buffa_unknown_fields.push( - ::buffa::encoding::decode_unknown_field(tag, buf, depth)? + ::buffa::encoding::decode_unknown_field(tag, buf, ctx)? ); } } } else { quote! { - _ => { ::buffa::encoding::skip_field_depth(tag, buf, depth)?; } + _ => { ::buffa::encoding::skip_field_depth(tag, buf, ctx.depth())?; } } }; @@ -689,7 +685,7 @@ pub fn generate_message_impl( &mut self, tag: ::buffa::encoding::Tag, buf: &mut impl ::buffa::bytes::Buf, - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result<(), ::buffa::DecodeError> { #[allow(unused_imports)] use ::buffa::bytes::Buf as _; @@ -1754,7 +1750,7 @@ fn scalar_merge_arm( ::buffa::Message::merge_length_delimited( self.#ident.get_or_insert_default(), buf, - depth, + ctx, )?; } }); @@ -1767,7 +1763,7 @@ fn scalar_merge_arm( ::buffa::Message::merge_group( self.#ident.get_or_insert_default(), buf, - depth, + ctx, #field_number, )?; } @@ -2071,7 +2067,7 @@ fn repeated_merge_arm( #field_number => { #wire_check let mut elem = ::core::default::Default::default(); - ::buffa::Message::merge_length_delimited(&mut elem, buf, depth)?; + ::buffa::Message::merge_length_delimited(&mut elem, buf, ctx)?; self.#ident.push(elem); } }); @@ -2086,7 +2082,7 @@ fn repeated_merge_arm( #field_number => { #wire_check let mut elem = ::core::default::Default::default(); - ::buffa::Message::merge_group(&mut elem, buf, depth, #field_number)?; + ::buffa::Message::merge_group(&mut elem, buf, ctx, #field_number)?; self.#ident.push(elem); } }); @@ -2478,10 +2474,10 @@ fn oneof_merge_arm( if let ::core::option::Option::Some( #enum_ident::#variant_ident(ref mut existing) ) = self.#field_ident { - ::buffa::Message::merge_length_delimited(#existing_ref, buf, depth)?; + ::buffa::Message::merge_length_delimited(#existing_ref, buf, ctx)?; } else { let mut val = ::core::default::Default::default(); - ::buffa::Message::merge_length_delimited(&mut val, buf, depth)?; + ::buffa::Message::merge_length_delimited(&mut val, buf, ctx)?; self.#field_ident = ::core::option::Option::Some( #enum_ident::#variant_ident(#wrapped_val) ); @@ -2494,10 +2490,10 @@ fn oneof_merge_arm( if let ::core::option::Option::Some( #enum_ident::#variant_ident(ref mut existing) ) = self.#field_ident { - ::buffa::Message::merge_group(#existing_ref, buf, depth, #field_number)?; + ::buffa::Message::merge_group(#existing_ref, buf, ctx, #field_number)?; } else { let mut val = ::core::default::Default::default(); - ::buffa::Message::merge_group(&mut val, buf, depth, #field_number)?; + ::buffa::Message::merge_group(&mut val, buf, ctx, #field_number)?; self.#field_ident = ::core::option::Option::Some( #enum_ident::#variant_ident(#wrapped_val) ); @@ -2733,7 +2729,7 @@ fn map_element_decode_stmt( } } Type::TYPE_MESSAGE => { - quote! { ::buffa::Message::merge_length_delimited(&mut #var, #buf_expr, depth)?; } + quote! { ::buffa::Message::merge_length_delimited(&mut #var, #buf_expr, ctx)?; } } _ => { let decode_fn = decode_fn_token(ty); @@ -2907,7 +2903,7 @@ fn map_merge_arm( match entry_tag.field_number() { 1 => { #decode_key } 2 => { #decode_val } - _ => { ::buffa::encoding::skip_field_depth(entry_tag, buf, depth)?; } + _ => { ::buffa::encoding::skip_field_depth(entry_tag, buf, ctx.depth())?; } } } // Correct the buffer position if the entry was not fully consumed. diff --git a/buffa-codegen/src/owned_view.rs b/buffa-codegen/src/owned_view.rs index 7236e1c1..f1acc7e5 100644 --- a/buffa-codegen/src/owned_view.rs +++ b/buffa-codegen/src/owned_view.rs @@ -273,8 +273,14 @@ pub(crate) fn generate_owned_view_wrapper( } /// Convert to the owned message type. - #[must_use] - pub fn to_owned_message(&self) -> #owned_path { + /// + /// # 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> { self.0.to_owned_message() } diff --git a/buffa-codegen/src/tests/view_codegen.rs b/buffa-codegen/src/tests/view_codegen.rs index fc5a3b77..b4f4c682 100644 --- a/buffa-codegen/src/tests/view_codegen.rs +++ b/buffa-codegen/src/tests/view_codegen.rs @@ -93,10 +93,10 @@ fn test_view_repeated_message_field() { content.contains("RepeatedView") && content.contains("ItemView"), "ContainerView.items must be RepeatedView: {content}" ); - // _decode_depth must be generated for both view types. + // _decode_ctx must be generated for both view types. assert!( - content.contains("fn _decode_depth"), - "missing _decode_depth impl: {content}" + content.contains("fn _decode_ctx"), + "missing _decode_ctx impl: {content}" ); } @@ -225,9 +225,9 @@ fn test_view_oneof_with_message_variant() { content.contains("BodyView") && content.contains("::buffa::alloc::boxed::Box<"), "Payload view must have boxed BodyView variant: {content}" ); - // Decode arm for the message variant must check recursion depth. + // Decode arm for the message variant must consume one recursion level. assert!( - content.contains("RecursionLimitExceeded"), + content.contains("ctx.descend()?"), "message-type oneof variant must check recursion depth: {content}" ); } diff --git a/buffa-codegen/src/view.rs b/buffa-codegen/src/view.rs index e69d6191..05c76728 100644 --- a/buffa-codegen/src/view.rs +++ b/buffa-codegen/src/view.rs @@ -37,7 +37,7 @@ fn closed_enum_view_unknown_route(preserve_unknown_fields: bool) -> TokenStream if preserve_unknown_fields { quote! { let __span_len = before_tag.len() - cur.len(); - view.__buffa_unknown_fields.push_raw(&before_tag[..__span_len]); + view.__buffa_unknown_fields.push_record(before_tag, __span_len, ctx)?; } } else { quote! {} @@ -237,7 +237,7 @@ pub(crate) fn generate_view_with_nesting( let unknown_field_handling = if ctx.config.preserve_unknown_fields { quote! { let span_len = before_tag.len() - cur.len(); - view.__buffa_unknown_fields.push_raw(&before_tag[..span_len]); + view.__buffa_unknown_fields.push_record(before_tag, span_len, ctx)?; } } else { quote! {} @@ -245,7 +245,7 @@ pub(crate) fn generate_view_with_nesting( // If no field borrows from 'a (all-scalar message with unknown-fields // preservation disabled), inject PhantomData<&'a ()> so the struct's - // lifetime param is used. _decode_depth(buf: &'a [u8]) requires 'a. + // lifetime param is used. _decode_ctx(buf: &'a [u8]) requires 'a. let phantom_field = if message_view_has_borrowing_field(ctx, msg, features, ctx.config.preserve_unknown_fields) { @@ -348,20 +348,22 @@ pub(crate) fn generate_view_with_nesting( #view_debug_impl impl<'a> #view_ident<'a> { - /// Decode from `buf`, enforcing a recursion depth limit for nested messages. + /// Decode from `buf` under the limits carried by `ctx` (recursion + /// depth and the shared unknown-field allowance). /// - /// Called by [`::buffa::MessageView::decode_view`] with [`::buffa::RECURSION_LIMIT`] - /// and by generated sub-message decode arms with `depth - 1`. + /// Called by [`::buffa::MessageView::decode_view`] with a fresh + /// default context and by generated sub-message decode arms with + /// `ctx.descend()?`. /// /// **Not part of the public API.** Named with a leading underscore to /// signal that it is for generated-code use only. #[doc(hidden)] - pub fn _decode_depth( + pub fn _decode_ctx( buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result { let mut view = Self::default(); - view._merge_into_view(buf, depth)?; + view._merge_into_view(buf, ctx)?; ::core::result::Result::Ok(view) } @@ -376,10 +378,11 @@ pub(crate) fn generate_view_with_nesting( pub fn _merge_into_view( &mut self, buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result<(), ::buffa::DecodeError> { - // `depth` may be unused for messages with no nested sub-message fields. - let _ = depth; + // `ctx` may be unused for messages with no nested sub-message + // fields and no unknown-field preservation. + let _ = ctx; // Rebind as `view` so the arm-generating functions (which emit // `view.#ident`) work unchanged. #[allow(unused_variables)] @@ -393,7 +396,7 @@ pub(crate) fn generate_view_with_nesting( #(#repeated_arms)* #(#oneof_arms)* _ => { - ::buffa::encoding::skip_field_depth(tag, &mut cur, depth)?; + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; #unknown_field_handling } } @@ -408,17 +411,23 @@ pub(crate) fn generate_view_with_nesting( fn decode_view( buf: &'a [u8], ) -> ::core::result::Result { - Self::_decode_depth(buf, ::buffa::RECURSION_LIMIT) + let __limit = ::core::cell::Cell::new(::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT); + Self::_decode_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit), + ) } - fn decode_view_with_limit( + fn decode_view_with_ctx( buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result { - Self::_decode_depth(buf, depth) + Self::_decode_ctx(buf, ctx) } - fn to_owned_message(&self) -> #owned_path { + fn to_owned_message( + &self, + ) -> ::core::result::Result<#owned_path, ::buffa::DecodeError> { self.to_owned_from_source(None) } @@ -429,14 +438,14 @@ pub(crate) fn generate_view_with_nesting( fn to_owned_from_source( &self, __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, - ) -> #owned_path { + ) -> ::core::result::Result<#owned_path, ::buffa::DecodeError> { #[allow(unused_imports)] use ::buffa::alloc::string::ToString as _; let _ = __buffa_src; - #owned_path { + ::core::result::Result::Ok(#owned_path { #(#owned_fields)* ..::core::default::Default::default() - } + }) } } @@ -716,7 +725,7 @@ pub(crate) fn oneof_view_needs_lifetime( /// Repeated, map, string, bytes, message, group fields all use `'a`. /// Only an all-scalar/enum message with `preserve_unknown_fields=false` /// has no borrowing fields — in that case a PhantomData marker is needed -/// to keep the `<'a>` lifetime valid for `_decode_depth(buf: &'a [u8])`. +/// to keep the `<'a>` lifetime valid for `_decode_ctx(buf: &'a [u8])`. fn message_view_has_borrowing_field( ctx: &CodeGenContext, msg: &DescriptorProto, @@ -1077,16 +1086,14 @@ fn scalar_decode_arm( Type::TYPE_MESSAGE => { let vt = resolve_view_decode_tokens(scope, field)?; quote! { - if depth == 0 { - return Err(::buffa::DecodeError::RecursionLimitExceeded); - } + let __sub_ctx = ctx.descend()?; let sub = ::buffa::types::borrow_bytes(&mut cur)?; // Proto merge semantics: if this field appeared before, // merge the new bytes into the existing view. match view.#ident.as_mut() { - Some(existing) => existing._merge_into_view(sub, depth - 1)?, + Some(existing) => existing._merge_into_view(sub, __sub_ctx)?, None => view.#ident = ::buffa::MessageFieldView::set( - #vt::_decode_depth(sub, depth - 1)? + #vt::_decode_ctx(sub, __sub_ctx)? ), } } @@ -1094,14 +1101,12 @@ fn scalar_decode_arm( Type::TYPE_GROUP => { let vt = resolve_view_decode_tokens(scope, field)?; quote! { - if depth == 0 { - return Err(::buffa::DecodeError::RecursionLimitExceeded); - } - let sub = ::buffa::types::borrow_group(&mut cur, #field_number, depth - 1)?; + let __sub_ctx = ctx.descend()?; + let sub = ::buffa::types::borrow_group(&mut cur, #field_number, __sub_ctx.depth())?; match view.#ident.as_mut() { - Some(existing) => existing._merge_into_view(sub, depth - 1)?, + Some(existing) => existing._merge_into_view(sub, __sub_ctx)?, None => view.#ident = ::buffa::MessageFieldView::set( - #vt::_decode_depth(sub, depth - 1)? + #vt::_decode_ctx(sub, __sub_ctx)? ), } } @@ -1145,11 +1150,9 @@ fn repeated_decode_arm( return Ok(quote! { #field_number => { #ld_check - if depth == 0 { - return Err(::buffa::DecodeError::RecursionLimitExceeded); - } + let __sub_ctx = ctx.descend()?; let sub = ::buffa::types::borrow_bytes(&mut cur)?; - view.#ident.push(#vt::_decode_depth(sub, depth - 1)?); + view.#ident.push(#vt::_decode_ctx(sub, __sub_ctx)?); } }); } @@ -1165,11 +1168,9 @@ fn repeated_decode_arm( return Ok(quote! { #field_number => { #sg_check - if depth == 0 { - return Err(::buffa::DecodeError::RecursionLimitExceeded); - } - let sub = ::buffa::types::borrow_group(&mut cur, #field_number, depth - 1)?; - view.#ident.push(#vt::_decode_depth(sub, depth - 1)?); + let __sub_ctx = ctx.descend()?; + let sub = ::buffa::types::borrow_group(&mut cur, #field_number, __sub_ctx.depth())?; + view.#ident.push(#vt::_decode_ctx(sub, __sub_ctx)?); } }); } @@ -1328,7 +1329,7 @@ fn map_decode_arm( match entry_tag.field_number() { 1 => { #decode_key } 2 => { #decode_val } - _ => { ::buffa::encoding::skip_field_depth(entry_tag, &mut entry_cur, depth)?; } + _ => { ::buffa::encoding::skip_field_depth(entry_tag, &mut entry_cur, ctx.depth())?; } } } view.#ident.push(key, val); @@ -1377,11 +1378,9 @@ fn map_view_entry_decode( Type::TYPE_MESSAGE => { let vt = resolve_view_decode_tokens(scope, fd)?; quote! { - if depth == 0 { - return Err(::buffa::DecodeError::RecursionLimitExceeded); - } + let __sub_ctx = ctx.descend()?; let sub = ::buffa::types::borrow_bytes(&mut entry_cur)?; - #var = #vt::_decode_depth(sub, depth - 1)?; + #var = #vt::_decode_ctx(sub, __sub_ctx)?; } } _ => { @@ -1432,16 +1431,14 @@ fn oneof_decode_arms( return Ok(quote! { #field_number => { #wire_check - if depth == 0 { - return Err(::buffa::DecodeError::RecursionLimitExceeded); - } + let __sub_ctx = ctx.descend()?; let sub = ::buffa::types::borrow_bytes(&mut cur)?; if let Some(#view_enum::#variant(ref mut existing)) = view.#field_ident { - existing._merge_into_view(sub, depth - 1)?; + existing._merge_into_view(sub, __sub_ctx)?; } else { view.#field_ident = Some(#view_enum::#variant( ::buffa::alloc::boxed::Box::new( - #vt::_decode_depth(sub, depth - 1)? + #vt::_decode_ctx(sub, __sub_ctx)? ) )); } @@ -1453,16 +1450,14 @@ fn oneof_decode_arms( return Ok(quote! { #field_number => { #wire_check - if depth == 0 { - return Err(::buffa::DecodeError::RecursionLimitExceeded); - } - let sub = ::buffa::types::borrow_group(&mut cur, #field_number, depth - 1)?; + let __sub_ctx = ctx.descend()?; + let sub = ::buffa::types::borrow_group(&mut cur, #field_number, __sub_ctx.depth())?; if let Some(#view_enum::#variant(ref mut existing)) = view.#field_ident { - existing._merge_into_view(sub, depth - 1)?; + existing._merge_into_view(sub, __sub_ctx)?; } else { view.#field_ident = Some(#view_enum::#variant( ::buffa::alloc::boxed::Box::new( - #vt::_decode_depth(sub, depth - 1)? + #vt::_decode_ctx(sub, __sub_ctx)? ) )); } @@ -1581,22 +1576,39 @@ fn build_to_owned_fields( }) .collect::, CodeGenError>>()?; - out.push(quote! { - #field_ident: self.#field_ident.as_ref().map(|v| match v { #(#match_arms)* }), + // Message-typed variants convert fallibly (`?` inside the arm), which + // a closure-based `Option::map` cannot propagate — use a `match` for + // those groups. Scalar-only groups keep `map` (clippy::manual_map + // fires on the match form when no `?` is present). + let has_fallible_variant = group.iter().any(|f| { + let t = effective_type(ctx, f, features); + t == Type::TYPE_MESSAGE || t == Type::TYPE_GROUP }); + if has_fallible_variant { + out.push(quote! { + #field_ident: match self.#field_ident.as_ref() { + ::core::option::Option::Some(v) => { + ::core::option::Option::Some(match v { #(#match_arms)* }) + } + ::core::option::Option::None => ::core::option::Option::None, + }, + }); + } else { + out.push(quote! { + #field_ident: self.#field_ident.as_ref().map(|v| match v { #(#match_arms)* }), + }); + } } // Emit `unknown_fields` conversion so round-trip via decode_view + // to_owned_message preserves unknown fields. `.into()` is a no-op when // the owned field is `UnknownFields`; when generate_json is on it wraps // in the per-message `__ExtJson` newtype (which has `From`). + // Errors (e.g. the unknown-field limit during re-materialization) + // propagate instead of silently dropping the fields. if preserve_unknown_fields { out.push(quote! { - __buffa_unknown_fields: self - .__buffa_unknown_fields - .to_owned() - .unwrap_or_default() - .into(), + __buffa_unknown_fields: self.__buffa_unknown_fields.to_owned()?.into(), }); } @@ -1673,7 +1685,7 @@ fn singular_to_owned( quote! { match self.#ident.as_option() { Some(v) => ::buffa::MessageField::<#owned_ty>::some( - v.to_owned_from_source(__buffa_src), + v.to_owned_from_source(__buffa_src)?, ), None => ::buffa::MessageField::none(), } @@ -1706,7 +1718,12 @@ fn repeated_to_owned( quote! { self.#ident.iter().map(|b| #conv).collect() } } Type::TYPE_MESSAGE | Type::TYPE_GROUP => { - quote! { self.#ident.iter().map(|v| v.to_owned_from_source(__buffa_src)).collect() } + quote! { + self.#ident + .iter() + .map(|v| v.to_owned_from_source(__buffa_src)) + .collect::<::core::result::Result<_, ::buffa::DecodeError>>()? + } } _ => quote! { self.#ident.to_vec() }, } @@ -1755,11 +1772,23 @@ fn map_to_owned_expr( Type::TYPE_MESSAGE => { // Verify the owned path resolves (catches missing imports at codegen time). let _owned_path = resolve_owned_path(scope, val_fd)?; - quote! { v.to_owned_from_source(__buffa_src) } + quote! { v.to_owned_from_source(__buffa_src)? } } _ => quote! { *v }, }; + // Message values convert fallibly; collect through Result so the `?` + // inside the closure has a Result-typed closure return to operate on. + if val_ty == Type::TYPE_MESSAGE { + return Ok(quote! { + self.#ident + .iter() + .map(|(k, v)| { + ::core::result::Result::<_, ::buffa::DecodeError>::Ok((#key_conv, #val_conv)) + }) + .collect::<::core::result::Result<_, ::buffa::DecodeError>>()? + }); + } Ok(quote! { self.#ident.iter().map(|(k, v)| (#key_conv, #val_conv)).collect() }) @@ -1786,7 +1815,7 @@ fn oneof_variant_to_owned( Type::TYPE_MESSAGE | Type::TYPE_GROUP => { // The owned variant is boxed unless opted out; `v` derefs through // the view's own `Box` either way, so only the wrapper differs. - let owned = quote! { v.to_owned_from_source(__buffa_src) }; + let owned = quote! { v.to_owned_from_source(__buffa_src)? }; if crate::oneof::variant_boxed( ctx, ty, 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 84eb89ab..dd5c1ba1 100644 --- a/buffa-descriptor/src/generated/google.protobuf.compiler.plugin.__view.rs +++ b/buffa-descriptor/src/generated/google.protobuf.compiler.plugin.__view.rs @@ -18,20 +18,22 @@ pub struct VersionView<'a> { pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, } impl<'a> VersionView<'a> { - /// Decode from `buf`, enforcing a recursion depth limit for nested messages. + /// Decode from `buf` under the limits carried by `ctx` (recursion + /// depth and the shared unknown-field allowance). /// - /// Called by [`::buffa::MessageView::decode_view`] with [`::buffa::RECURSION_LIMIT`] - /// and by generated sub-message decode arms with `depth - 1`. + /// Called by [`::buffa::MessageView::decode_view`] with a fresh + /// default context and by generated sub-message decode arms with + /// `ctx.descend()?`. /// /// **Not part of the public API.** Named with a leading underscore to /// signal that it is for generated-code use only. #[doc(hidden)] - pub fn _decode_depth( + pub fn _decode_ctx( buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result { let mut view = Self::default(); - view._merge_into_view(buf, depth)?; + view._merge_into_view(buf, ctx)?; ::core::result::Result::Ok(view) } /// Merge fields from `buf` into this view (proto merge semantics). @@ -45,9 +47,9 @@ impl<'a> VersionView<'a> { pub fn _merge_into_view( &mut self, buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result<(), ::buffa::DecodeError> { - let _ = depth; + let _ = ctx; #[allow(unused_variables)] let view = self; let mut cur: &'a [u8] = buf; @@ -96,9 +98,9 @@ impl<'a> VersionView<'a> { view.suffix = Some(::buffa::types::borrow_str(&mut cur)?); } _ => { - ::buffa::encoding::skip_field_depth(tag, &mut cur, depth)?; + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; let span_len = before_tag.len() - cur.len(); - view.__buffa_unknown_fields.push_raw(&before_tag[..span_len]); + view.__buffa_unknown_fields.push_record(before_tag, span_len, ctx)?; } } } @@ -108,37 +110,39 @@ impl<'a> VersionView<'a> { impl<'a> ::buffa::MessageView<'a> for VersionView<'a> { type Owned = super::super::Version; fn decode_view(buf: &'a [u8]) -> ::core::result::Result { - Self::_decode_depth(buf, ::buffa::RECURSION_LIMIT) + let __limit = ::core::cell::Cell::new(::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT); + Self::_decode_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit), + ) } - fn decode_view_with_limit( + fn decode_view_with_ctx( buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result { - Self::_decode_depth(buf, depth) + Self::_decode_ctx(buf, ctx) } - fn to_owned_message(&self) -> super::super::Version { + fn to_owned_message( + &self, + ) -> ::core::result::Result { self.to_owned_from_source(None) } #[allow(clippy::useless_conversion, clippy::needless_update)] fn to_owned_from_source( &self, __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, - ) -> super::super::Version { + ) -> ::core::result::Result { #[allow(unused_imports)] use ::buffa::alloc::string::ToString as _; let _ = __buffa_src; - super::super::Version { + ::core::result::Result::Ok(super::super::Version { major: self.major, minor: self.minor, patch: self.patch, suffix: self.suffix.map(|s| s.to_string()), - __buffa_unknown_fields: self - .__buffa_unknown_fields - .to_owned() - .unwrap_or_default() - .into(), + __buffa_unknown_fields: self.__buffa_unknown_fields.to_owned()?.into(), ..::core::default::Default::default() - } + }) } } impl<'a> ::buffa::ViewEncode<'a> for VersionView<'a> { @@ -337,8 +341,14 @@ impl VersionOwnedView { self.0.reborrow() } /// Convert to the owned message type. - #[must_use] - pub fn to_owned_message(&self) -> super::super::Version { + /// + /// # 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 { self.0.to_owned_message() } /// The underlying bytes buffer. @@ -462,20 +472,22 @@ pub struct CodeGeneratorRequestView<'a> { pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, } impl<'a> CodeGeneratorRequestView<'a> { - /// Decode from `buf`, enforcing a recursion depth limit for nested messages. + /// Decode from `buf` under the limits carried by `ctx` (recursion + /// depth and the shared unknown-field allowance). /// - /// Called by [`::buffa::MessageView::decode_view`] with [`::buffa::RECURSION_LIMIT`] - /// and by generated sub-message decode arms with `depth - 1`. + /// Called by [`::buffa::MessageView::decode_view`] with a fresh + /// default context and by generated sub-message decode arms with + /// `ctx.descend()?`. /// /// **Not part of the public API.** Named with a leading underscore to /// signal that it is for generated-code use only. #[doc(hidden)] - pub fn _decode_depth( + pub fn _decode_ctx( buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result { let mut view = Self::default(); - view._merge_into_view(buf, depth)?; + view._merge_into_view(buf, ctx)?; ::core::result::Result::Ok(view) } /// Merge fields from `buf` into this view (proto merge semantics). @@ -489,9 +501,9 @@ impl<'a> CodeGeneratorRequestView<'a> { pub fn _merge_into_view( &mut self, buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result<(), ::buffa::DecodeError> { - let _ = depth; + let _ = ctx; #[allow(unused_variables)] let view = self; let mut cur: &'a [u8] = buf; @@ -517,17 +529,15 @@ impl<'a> CodeGeneratorRequestView<'a> { actual: tag.wire_type() as u8, }); } - if depth == 0 { - return Err(::buffa::DecodeError::RecursionLimitExceeded); - } + let __sub_ctx = ctx.descend()?; let sub = ::buffa::types::borrow_bytes(&mut cur)?; match view.compiler_version.as_mut() { - Some(existing) => existing._merge_into_view(sub, depth - 1)?, + Some(existing) => existing._merge_into_view(sub, __sub_ctx)?, None => { view.compiler_version = ::buffa::MessageFieldView::set( - super::super::__buffa::view::VersionView::_decode_depth( + super::super::__buffa::view::VersionView::_decode_ctx( sub, - depth - 1, + __sub_ctx, )?, ); } @@ -551,15 +561,13 @@ impl<'a> CodeGeneratorRequestView<'a> { actual: tag.wire_type() as u8, }); } - if depth == 0 { - return Err(::buffa::DecodeError::RecursionLimitExceeded); - } + let __sub_ctx = ctx.descend()?; let sub = ::buffa::types::borrow_bytes(&mut cur)?; view.proto_file .push( - super::super::super::__buffa::view::FileDescriptorProtoView::_decode_depth( + super::super::super::__buffa::view::FileDescriptorProtoView::_decode_ctx( sub, - depth - 1, + __sub_ctx, )?, ); } @@ -571,22 +579,20 @@ impl<'a> CodeGeneratorRequestView<'a> { actual: tag.wire_type() as u8, }); } - if depth == 0 { - return Err(::buffa::DecodeError::RecursionLimitExceeded); - } + let __sub_ctx = ctx.descend()?; let sub = ::buffa::types::borrow_bytes(&mut cur)?; view.source_file_descriptors .push( - super::super::super::__buffa::view::FileDescriptorProtoView::_decode_depth( + super::super::super::__buffa::view::FileDescriptorProtoView::_decode_ctx( sub, - depth - 1, + __sub_ctx, )?, ); } _ => { - ::buffa::encoding::skip_field_depth(tag, &mut cur, depth)?; + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; let span_len = before_tag.len() - cur.len(); - view.__buffa_unknown_fields.push_raw(&before_tag[..span_len]); + view.__buffa_unknown_fields.push_record(before_tag, span_len, ctx)?; } } } @@ -596,26 +602,38 @@ impl<'a> CodeGeneratorRequestView<'a> { impl<'a> ::buffa::MessageView<'a> for CodeGeneratorRequestView<'a> { type Owned = super::super::CodeGeneratorRequest; fn decode_view(buf: &'a [u8]) -> ::core::result::Result { - Self::_decode_depth(buf, ::buffa::RECURSION_LIMIT) + let __limit = ::core::cell::Cell::new(::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT); + Self::_decode_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit), + ) } - fn decode_view_with_limit( + fn decode_view_with_ctx( buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result { - Self::_decode_depth(buf, depth) + Self::_decode_ctx(buf, ctx) } - fn to_owned_message(&self) -> super::super::CodeGeneratorRequest { + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::CodeGeneratorRequest, + ::buffa::DecodeError, + > { self.to_owned_from_source(None) } #[allow(clippy::useless_conversion, clippy::needless_update)] fn to_owned_from_source( &self, __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, - ) -> super::super::CodeGeneratorRequest { + ) -> ::core::result::Result< + super::super::CodeGeneratorRequest, + ::buffa::DecodeError, + > { #[allow(unused_imports)] use ::buffa::alloc::string::ToString as _; let _ = __buffa_src; - super::super::CodeGeneratorRequest { + ::core::result::Result::Ok(super::super::CodeGeneratorRequest { file_to_generate: self .file_to_generate .iter() @@ -626,27 +644,23 @@ impl<'a> ::buffa::MessageView<'a> for CodeGeneratorRequestView<'a> { .proto_file .iter() .map(|v| v.to_owned_from_source(__buffa_src)) - .collect(), + .collect::<::core::result::Result<_, ::buffa::DecodeError>>()?, source_file_descriptors: self .source_file_descriptors .iter() .map(|v| v.to_owned_from_source(__buffa_src)) - .collect(), + .collect::<::core::result::Result<_, ::buffa::DecodeError>>()?, compiler_version: match self.compiler_version.as_option() { Some(v) => { ::buffa::MessageField::< super::super::Version, - >::some(v.to_owned_from_source(__buffa_src)) + >::some(v.to_owned_from_source(__buffa_src)?) } None => ::buffa::MessageField::none(), }, - __buffa_unknown_fields: self - .__buffa_unknown_fields - .to_owned() - .unwrap_or_default() - .into(), + __buffa_unknown_fields: self.__buffa_unknown_fields.to_owned()?.into(), ..::core::default::Default::default() - } + }) } } impl<'a> ::buffa::ViewEncode<'a> for CodeGeneratorRequestView<'a> { @@ -872,8 +886,17 @@ impl CodeGeneratorRequestOwnedView { self.0.reborrow() } /// Convert to the owned message type. - #[must_use] - pub fn to_owned_message(&self) -> super::super::CodeGeneratorRequest { + /// + /// # 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, + > { self.0.to_owned_message() } /// The underlying bytes buffer. @@ -1028,20 +1051,22 @@ pub struct CodeGeneratorResponseView<'a> { pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, } impl<'a> CodeGeneratorResponseView<'a> { - /// Decode from `buf`, enforcing a recursion depth limit for nested messages. + /// Decode from `buf` under the limits carried by `ctx` (recursion + /// depth and the shared unknown-field allowance). /// - /// Called by [`::buffa::MessageView::decode_view`] with [`::buffa::RECURSION_LIMIT`] - /// and by generated sub-message decode arms with `depth - 1`. + /// Called by [`::buffa::MessageView::decode_view`] with a fresh + /// default context and by generated sub-message decode arms with + /// `ctx.descend()?`. /// /// **Not part of the public API.** Named with a leading underscore to /// signal that it is for generated-code use only. #[doc(hidden)] - pub fn _decode_depth( + pub fn _decode_ctx( buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result { let mut view = Self::default(); - view._merge_into_view(buf, depth)?; + view._merge_into_view(buf, ctx)?; ::core::result::Result::Ok(view) } /// Merge fields from `buf` into this view (proto merge semantics). @@ -1055,9 +1080,9 @@ impl<'a> CodeGeneratorResponseView<'a> { pub fn _merge_into_view( &mut self, buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result<(), ::buffa::DecodeError> { - let _ = depth; + let _ = ctx; #[allow(unused_variables)] let view = self; let mut cur: &'a [u8] = buf; @@ -1115,22 +1140,20 @@ impl<'a> CodeGeneratorResponseView<'a> { actual: tag.wire_type() as u8, }); } - if depth == 0 { - return Err(::buffa::DecodeError::RecursionLimitExceeded); - } + let __sub_ctx = ctx.descend()?; let sub = ::buffa::types::borrow_bytes(&mut cur)?; view.file .push( - super::super::__buffa::view::code_generator_response::FileView::_decode_depth( + super::super::__buffa::view::code_generator_response::FileView::_decode_ctx( sub, - depth - 1, + __sub_ctx, )?, ); } _ => { - ::buffa::encoding::skip_field_depth(tag, &mut cur, depth)?; + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; let span_len = before_tag.len() - cur.len(); - view.__buffa_unknown_fields.push_raw(&before_tag[..span_len]); + view.__buffa_unknown_fields.push_record(before_tag, span_len, ctx)?; } } } @@ -1140,26 +1163,38 @@ impl<'a> CodeGeneratorResponseView<'a> { impl<'a> ::buffa::MessageView<'a> for CodeGeneratorResponseView<'a> { type Owned = super::super::CodeGeneratorResponse; fn decode_view(buf: &'a [u8]) -> ::core::result::Result { - Self::_decode_depth(buf, ::buffa::RECURSION_LIMIT) + let __limit = ::core::cell::Cell::new(::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT); + Self::_decode_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit), + ) } - fn decode_view_with_limit( + fn decode_view_with_ctx( buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result { - Self::_decode_depth(buf, depth) + Self::_decode_ctx(buf, ctx) } - fn to_owned_message(&self) -> super::super::CodeGeneratorResponse { + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::CodeGeneratorResponse, + ::buffa::DecodeError, + > { self.to_owned_from_source(None) } #[allow(clippy::useless_conversion, clippy::needless_update)] fn to_owned_from_source( &self, __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, - ) -> super::super::CodeGeneratorResponse { + ) -> ::core::result::Result< + super::super::CodeGeneratorResponse, + ::buffa::DecodeError, + > { #[allow(unused_imports)] use ::buffa::alloc::string::ToString as _; let _ = __buffa_src; - super::super::CodeGeneratorResponse { + ::core::result::Result::Ok(super::super::CodeGeneratorResponse { error: self.error.map(|s| s.to_string()), supported_features: self.supported_features, minimum_edition: self.minimum_edition, @@ -1168,14 +1203,10 @@ impl<'a> ::buffa::MessageView<'a> for CodeGeneratorResponseView<'a> { .file .iter() .map(|v| v.to_owned_from_source(__buffa_src)) - .collect(), - __buffa_unknown_fields: self - .__buffa_unknown_fields - .to_owned() - .unwrap_or_default() - .into(), + .collect::<::core::result::Result<_, ::buffa::DecodeError>>()?, + __buffa_unknown_fields: self.__buffa_unknown_fields.to_owned()?.into(), ..::core::default::Default::default() - } + }) } } impl<'a> ::buffa::ViewEncode<'a> for CodeGeneratorResponseView<'a> { @@ -1400,8 +1431,17 @@ impl CodeGeneratorResponseOwnedView { self.0.reborrow() } /// Convert to the owned message type. - #[must_use] - pub fn to_owned_message(&self) -> super::super::CodeGeneratorResponse { + /// + /// # 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, + > { self.0.to_owned_message() } /// The underlying bytes buffer. @@ -1573,20 +1613,22 @@ pub mod code_generator_response { pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, } impl<'a> FileView<'a> { - /// Decode from `buf`, enforcing a recursion depth limit for nested messages. + /// Decode from `buf` under the limits carried by `ctx` (recursion + /// depth and the shared unknown-field allowance). /// - /// Called by [`::buffa::MessageView::decode_view`] with [`::buffa::RECURSION_LIMIT`] - /// and by generated sub-message decode arms with `depth - 1`. + /// Called by [`::buffa::MessageView::decode_view`] with a fresh + /// default context and by generated sub-message decode arms with + /// `ctx.descend()?`. /// /// **Not part of the public API.** Named with a leading underscore to /// signal that it is for generated-code use only. #[doc(hidden)] - pub fn _decode_depth( + pub fn _decode_ctx( buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result { let mut view = Self::default(); - view._merge_into_view(buf, depth)?; + view._merge_into_view(buf, ctx)?; ::core::result::Result::Ok(view) } /// Merge fields from `buf` into this view (proto merge semantics). @@ -1600,9 +1642,9 @@ pub mod code_generator_response { pub fn _merge_into_view( &mut self, buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result<(), ::buffa::DecodeError> { - let _ = depth; + let _ = ctx; #[allow(unused_variables)] let view = self; let mut cur: &'a [u8] = buf; @@ -1658,26 +1700,25 @@ pub mod code_generator_response { actual: tag.wire_type() as u8, }); } - if depth == 0 { - return Err(::buffa::DecodeError::RecursionLimitExceeded); - } + let __sub_ctx = ctx.descend()?; let sub = ::buffa::types::borrow_bytes(&mut cur)?; match view.generated_code_info.as_mut() { - Some(existing) => existing._merge_into_view(sub, depth - 1)?, + Some(existing) => existing._merge_into_view(sub, __sub_ctx)?, None => { view.generated_code_info = ::buffa::MessageFieldView::set( - super::super::super::super::__buffa::view::GeneratedCodeInfoView::_decode_depth( + super::super::super::super::__buffa::view::GeneratedCodeInfoView::_decode_ctx( sub, - depth - 1, + __sub_ctx, )?, ); } } } _ => { - ::buffa::encoding::skip_field_depth(tag, &mut cur, depth)?; + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; let span_len = before_tag.len() - cur.len(); - view.__buffa_unknown_fields.push_raw(&before_tag[..span_len]); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; } } } @@ -1689,28 +1730,38 @@ pub mod code_generator_response { fn decode_view( buf: &'a [u8], ) -> ::core::result::Result { - Self::_decode_depth(buf, ::buffa::RECURSION_LIMIT) + let __limit = ::core::cell::Cell::new(::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT); + Self::_decode_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit), + ) } - fn decode_view_with_limit( + fn decode_view_with_ctx( buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result { - Self::_decode_depth(buf, depth) + Self::_decode_ctx(buf, ctx) } fn to_owned_message( &self, - ) -> super::super::super::code_generator_response::File { + ) -> ::core::result::Result< + super::super::super::code_generator_response::File, + ::buffa::DecodeError, + > { self.to_owned_from_source(None) } #[allow(clippy::useless_conversion, clippy::needless_update)] fn to_owned_from_source( &self, __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, - ) -> super::super::super::code_generator_response::File { + ) -> ::core::result::Result< + super::super::super::code_generator_response::File, + ::buffa::DecodeError, + > { #[allow(unused_imports)] use ::buffa::alloc::string::ToString as _; let _ = __buffa_src; - super::super::super::code_generator_response::File { + ::core::result::Result::Ok(super::super::super::code_generator_response::File { name: self.name.map(|s| s.to_string()), insertion_point: self.insertion_point.map(|s| s.to_string()), content: self.content.map(|s| s.to_string()), @@ -1718,17 +1769,13 @@ pub mod code_generator_response { Some(v) => { ::buffa::MessageField::< super::super::super::super::GeneratedCodeInfo, - >::some(v.to_owned_from_source(__buffa_src)) + >::some(v.to_owned_from_source(__buffa_src)?) } None => ::buffa::MessageField::none(), }, - __buffa_unknown_fields: self - .__buffa_unknown_fields - .to_owned() - .unwrap_or_default() - .into(), + __buffa_unknown_fields: self.__buffa_unknown_fields.to_owned()?.into(), ..::core::default::Default::default() - } + }) } } impl<'a> ::buffa::ViewEncode<'a> for FileView<'a> { @@ -1920,10 +1967,17 @@ pub mod code_generator_response { self.0.reborrow() } /// Convert to the owned message type. - #[must_use] + /// + /// # 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, - ) -> super::super::super::code_generator_response::File { + ) -> ::core::result::Result< + super::super::super::code_generator_response::File, + ::buffa::DecodeError, + > { self.0.to_owned_message() } /// The underlying bytes buffer. diff --git a/buffa-descriptor/src/generated/google.protobuf.compiler.plugin.rs b/buffa-descriptor/src/generated/google.protobuf.compiler.plugin.rs index a09fdf85..b7bed3cc 100644 --- a/buffa-descriptor/src/generated/google.protobuf.compiler.plugin.rs +++ b/buffa-descriptor/src/generated/google.protobuf.compiler.plugin.rs @@ -174,7 +174,7 @@ impl ::buffa::Message for Version { &mut self, tag: ::buffa::encoding::Tag, buf: &mut impl ::buffa::bytes::Buf, - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result<(), ::buffa::DecodeError> { #[allow(unused_imports)] use ::buffa::bytes::Buf as _; @@ -232,7 +232,7 @@ impl ::buffa::Message for Version { } _ => { self.__buffa_unknown_fields - .push(::buffa::encoding::decode_unknown_field(tag, buf, depth)?); + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); } } ::core::result::Result::Ok(()) @@ -568,7 +568,7 @@ impl ::buffa::Message for CodeGeneratorRequest { &mut self, tag: ::buffa::encoding::Tag, buf: &mut impl ::buffa::bytes::Buf, - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result<(), ::buffa::DecodeError> { #[allow(unused_imports)] use ::buffa::bytes::Buf as _; @@ -611,7 +611,7 @@ impl ::buffa::Message for CodeGeneratorRequest { ::buffa::Message::merge_length_delimited( self.compiler_version.get_or_insert_default(), buf, - depth, + ctx, )?; } 15u32 => { @@ -623,7 +623,7 @@ impl ::buffa::Message for CodeGeneratorRequest { }); } let mut elem = ::core::default::Default::default(); - ::buffa::Message::merge_length_delimited(&mut elem, buf, depth)?; + ::buffa::Message::merge_length_delimited(&mut elem, buf, ctx)?; self.proto_file.push(elem); } 17u32 => { @@ -635,12 +635,12 @@ impl ::buffa::Message for CodeGeneratorRequest { }); } let mut elem = ::core::default::Default::default(); - ::buffa::Message::merge_length_delimited(&mut elem, buf, depth)?; + ::buffa::Message::merge_length_delimited(&mut elem, buf, ctx)?; self.source_file_descriptors.push(elem); } _ => { self.__buffa_unknown_fields - .push(::buffa::encoding::decode_unknown_field(tag, buf, depth)?); + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); } } ::core::result::Result::Ok(()) @@ -994,7 +994,7 @@ impl ::buffa::Message for CodeGeneratorResponse { &mut self, tag: ::buffa::encoding::Tag, buf: &mut impl ::buffa::bytes::Buf, - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result<(), ::buffa::DecodeError> { #[allow(unused_imports)] use ::buffa::bytes::Buf as _; @@ -1059,12 +1059,12 @@ impl ::buffa::Message for CodeGeneratorResponse { }); } let mut elem = ::core::default::Default::default(); - ::buffa::Message::merge_length_delimited(&mut elem, buf, depth)?; + ::buffa::Message::merge_length_delimited(&mut elem, buf, ctx)?; self.file.push(elem); } _ => { self.__buffa_unknown_fields - .push(::buffa::encoding::decode_unknown_field(tag, buf, depth)?); + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); } } ::core::result::Result::Ok(()) @@ -1589,7 +1589,7 @@ pub mod code_generator_response { &mut self, tag: ::buffa::encoding::Tag, buf: &mut impl ::buffa::bytes::Buf, - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result<(), ::buffa::DecodeError> { #[allow(unused_imports)] use ::buffa::bytes::Buf as _; @@ -1652,12 +1652,12 @@ pub mod code_generator_response { ::buffa::Message::merge_length_delimited( self.generated_code_info.get_or_insert_default(), buf, - depth, + ctx, )?; } _ => { self.__buffa_unknown_fields - .push(::buffa::encoding::decode_unknown_field(tag, buf, depth)?); + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); } } ::core::result::Result::Ok(()) diff --git a/buffa-descriptor/src/generated/google.protobuf.descriptor.__view.rs b/buffa-descriptor/src/generated/google.protobuf.descriptor.__view.rs index a17c7cc2..6ad2288b 100644 --- a/buffa-descriptor/src/generated/google.protobuf.descriptor.__view.rs +++ b/buffa-descriptor/src/generated/google.protobuf.descriptor.__view.rs @@ -13,20 +13,22 @@ pub struct FileDescriptorSetView<'a> { pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, } impl<'a> FileDescriptorSetView<'a> { - /// Decode from `buf`, enforcing a recursion depth limit for nested messages. + /// Decode from `buf` under the limits carried by `ctx` (recursion + /// depth and the shared unknown-field allowance). /// - /// Called by [`::buffa::MessageView::decode_view`] with [`::buffa::RECURSION_LIMIT`] - /// and by generated sub-message decode arms with `depth - 1`. + /// Called by [`::buffa::MessageView::decode_view`] with a fresh + /// default context and by generated sub-message decode arms with + /// `ctx.descend()?`. /// /// **Not part of the public API.** Named with a leading underscore to /// signal that it is for generated-code use only. #[doc(hidden)] - pub fn _decode_depth( + pub fn _decode_ctx( buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result { let mut view = Self::default(); - view._merge_into_view(buf, depth)?; + view._merge_into_view(buf, ctx)?; ::core::result::Result::Ok(view) } /// Merge fields from `buf` into this view (proto merge semantics). @@ -40,9 +42,9 @@ impl<'a> FileDescriptorSetView<'a> { pub fn _merge_into_view( &mut self, buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result<(), ::buffa::DecodeError> { - let _ = depth; + let _ = ctx; #[allow(unused_variables)] let view = self; let mut cur: &'a [u8] = buf; @@ -58,22 +60,20 @@ impl<'a> FileDescriptorSetView<'a> { actual: tag.wire_type() as u8, }); } - if depth == 0 { - return Err(::buffa::DecodeError::RecursionLimitExceeded); - } + let __sub_ctx = ctx.descend()?; let sub = ::buffa::types::borrow_bytes(&mut cur)?; view.file .push( - super::super::__buffa::view::FileDescriptorProtoView::_decode_depth( + super::super::__buffa::view::FileDescriptorProtoView::_decode_ctx( sub, - depth - 1, + __sub_ctx, )?, ); } _ => { - ::buffa::encoding::skip_field_depth(tag, &mut cur, depth)?; + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; let span_len = before_tag.len() - cur.len(); - view.__buffa_unknown_fields.push_raw(&before_tag[..span_len]); + view.__buffa_unknown_fields.push_record(before_tag, span_len, ctx)?; } } } @@ -83,38 +83,40 @@ impl<'a> FileDescriptorSetView<'a> { impl<'a> ::buffa::MessageView<'a> for FileDescriptorSetView<'a> { type Owned = super::super::FileDescriptorSet; fn decode_view(buf: &'a [u8]) -> ::core::result::Result { - Self::_decode_depth(buf, ::buffa::RECURSION_LIMIT) + let __limit = ::core::cell::Cell::new(::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT); + Self::_decode_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit), + ) } - fn decode_view_with_limit( + fn decode_view_with_ctx( buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result { - Self::_decode_depth(buf, depth) + Self::_decode_ctx(buf, ctx) } - fn to_owned_message(&self) -> super::super::FileDescriptorSet { + fn to_owned_message( + &self, + ) -> ::core::result::Result { self.to_owned_from_source(None) } #[allow(clippy::useless_conversion, clippy::needless_update)] fn to_owned_from_source( &self, __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, - ) -> super::super::FileDescriptorSet { + ) -> ::core::result::Result { #[allow(unused_imports)] use ::buffa::alloc::string::ToString as _; let _ = __buffa_src; - super::super::FileDescriptorSet { + ::core::result::Result::Ok(super::super::FileDescriptorSet { file: self .file .iter() .map(|v| v.to_owned_from_source(__buffa_src)) - .collect(), - __buffa_unknown_fields: self - .__buffa_unknown_fields - .to_owned() - .unwrap_or_default() - .into(), + .collect::<::core::result::Result<_, ::buffa::DecodeError>>()?, + __buffa_unknown_fields: self.__buffa_unknown_fields.to_owned()?.into(), ..::core::default::Default::default() - } + }) } } impl<'a> ::buffa::ViewEncode<'a> for FileDescriptorSetView<'a> { @@ -265,8 +267,14 @@ impl FileDescriptorSetOwnedView { self.0.reborrow() } /// Convert to the owned message type. - #[must_use] - pub fn to_owned_message(&self) -> super::super::FileDescriptorSet { + /// + /// # 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 { self.0.to_owned_message() } /// The underlying bytes buffer. @@ -405,20 +413,22 @@ pub struct FileDescriptorProtoView<'a> { pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, } impl<'a> FileDescriptorProtoView<'a> { - /// Decode from `buf`, enforcing a recursion depth limit for nested messages. + /// Decode from `buf` under the limits carried by `ctx` (recursion + /// depth and the shared unknown-field allowance). /// - /// Called by [`::buffa::MessageView::decode_view`] with [`::buffa::RECURSION_LIMIT`] - /// and by generated sub-message decode arms with `depth - 1`. + /// Called by [`::buffa::MessageView::decode_view`] with a fresh + /// default context and by generated sub-message decode arms with + /// `ctx.descend()?`. /// /// **Not part of the public API.** Named with a leading underscore to /// signal that it is for generated-code use only. #[doc(hidden)] - pub fn _decode_depth( + pub fn _decode_ctx( buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result { let mut view = Self::default(); - view._merge_into_view(buf, depth)?; + view._merge_into_view(buf, ctx)?; ::core::result::Result::Ok(view) } /// Merge fields from `buf` into this view (proto merge semantics). @@ -432,9 +442,9 @@ impl<'a> FileDescriptorProtoView<'a> { pub fn _merge_into_view( &mut self, buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result<(), ::buffa::DecodeError> { - let _ = depth; + let _ = ctx; #[allow(unused_variables)] let view = self; let mut cur: &'a [u8] = buf; @@ -470,17 +480,15 @@ impl<'a> FileDescriptorProtoView<'a> { actual: tag.wire_type() as u8, }); } - if depth == 0 { - return Err(::buffa::DecodeError::RecursionLimitExceeded); - } + let __sub_ctx = ctx.descend()?; let sub = ::buffa::types::borrow_bytes(&mut cur)?; match view.options.as_mut() { - Some(existing) => existing._merge_into_view(sub, depth - 1)?, + Some(existing) => existing._merge_into_view(sub, __sub_ctx)?, None => { view.options = ::buffa::MessageFieldView::set( - super::super::__buffa::view::FileOptionsView::_decode_depth( + super::super::__buffa::view::FileOptionsView::_decode_ctx( sub, - depth - 1, + __sub_ctx, )?, ); } @@ -494,17 +502,15 @@ impl<'a> FileDescriptorProtoView<'a> { actual: tag.wire_type() as u8, }); } - if depth == 0 { - return Err(::buffa::DecodeError::RecursionLimitExceeded); - } + let __sub_ctx = ctx.descend()?; let sub = ::buffa::types::borrow_bytes(&mut cur)?; match view.source_code_info.as_mut() { - Some(existing) => existing._merge_into_view(sub, depth - 1)?, + Some(existing) => existing._merge_into_view(sub, __sub_ctx)?, None => { view.source_code_info = ::buffa::MessageFieldView::set( - super::super::__buffa::view::SourceCodeInfoView::_decode_depth( + super::super::__buffa::view::SourceCodeInfoView::_decode_ctx( sub, - depth - 1, + __sub_ctx, )?, ); } @@ -535,7 +541,8 @@ impl<'a> FileDescriptorProtoView<'a> { view.edition = Some(__v); } else { let __span_len = before_tag.len() - cur.len(); - view.__buffa_unknown_fields.push_raw(&before_tag[..__span_len]); + view.__buffa_unknown_fields + .push_record(before_tag, __span_len, ctx)?; } } 3u32 => { @@ -606,15 +613,13 @@ impl<'a> FileDescriptorProtoView<'a> { actual: tag.wire_type() as u8, }); } - if depth == 0 { - return Err(::buffa::DecodeError::RecursionLimitExceeded); - } + let __sub_ctx = ctx.descend()?; let sub = ::buffa::types::borrow_bytes(&mut cur)?; view.message_type .push( - super::super::__buffa::view::DescriptorProtoView::_decode_depth( + super::super::__buffa::view::DescriptorProtoView::_decode_ctx( sub, - depth - 1, + __sub_ctx, )?, ); } @@ -626,15 +631,13 @@ impl<'a> FileDescriptorProtoView<'a> { actual: tag.wire_type() as u8, }); } - if depth == 0 { - return Err(::buffa::DecodeError::RecursionLimitExceeded); - } + let __sub_ctx = ctx.descend()?; let sub = ::buffa::types::borrow_bytes(&mut cur)?; view.enum_type .push( - super::super::__buffa::view::EnumDescriptorProtoView::_decode_depth( + super::super::__buffa::view::EnumDescriptorProtoView::_decode_ctx( sub, - depth - 1, + __sub_ctx, )?, ); } @@ -646,15 +649,13 @@ impl<'a> FileDescriptorProtoView<'a> { actual: tag.wire_type() as u8, }); } - if depth == 0 { - return Err(::buffa::DecodeError::RecursionLimitExceeded); - } + let __sub_ctx = ctx.descend()?; let sub = ::buffa::types::borrow_bytes(&mut cur)?; view.service .push( - super::super::__buffa::view::ServiceDescriptorProtoView::_decode_depth( + super::super::__buffa::view::ServiceDescriptorProtoView::_decode_ctx( sub, - depth - 1, + __sub_ctx, )?, ); } @@ -666,22 +667,20 @@ impl<'a> FileDescriptorProtoView<'a> { actual: tag.wire_type() as u8, }); } - if depth == 0 { - return Err(::buffa::DecodeError::RecursionLimitExceeded); - } + let __sub_ctx = ctx.descend()?; let sub = ::buffa::types::borrow_bytes(&mut cur)?; view.extension .push( - super::super::__buffa::view::FieldDescriptorProtoView::_decode_depth( + super::super::__buffa::view::FieldDescriptorProtoView::_decode_ctx( sub, - depth - 1, + __sub_ctx, )?, ); } _ => { - ::buffa::encoding::skip_field_depth(tag, &mut cur, depth)?; + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; let span_len = before_tag.len() - cur.len(); - view.__buffa_unknown_fields.push_raw(&before_tag[..span_len]); + view.__buffa_unknown_fields.push_record(before_tag, span_len, ctx)?; } } } @@ -691,26 +690,38 @@ impl<'a> FileDescriptorProtoView<'a> { impl<'a> ::buffa::MessageView<'a> for FileDescriptorProtoView<'a> { type Owned = super::super::FileDescriptorProto; fn decode_view(buf: &'a [u8]) -> ::core::result::Result { - Self::_decode_depth(buf, ::buffa::RECURSION_LIMIT) + let __limit = ::core::cell::Cell::new(::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT); + Self::_decode_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit), + ) } - fn decode_view_with_limit( + fn decode_view_with_ctx( buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result { - Self::_decode_depth(buf, depth) + Self::_decode_ctx(buf, ctx) } - fn to_owned_message(&self) -> super::super::FileDescriptorProto { + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::FileDescriptorProto, + ::buffa::DecodeError, + > { self.to_owned_from_source(None) } #[allow(clippy::useless_conversion, clippy::needless_update)] fn to_owned_from_source( &self, __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, - ) -> super::super::FileDescriptorProto { + ) -> ::core::result::Result< + super::super::FileDescriptorProto, + ::buffa::DecodeError, + > { #[allow(unused_imports)] use ::buffa::alloc::string::ToString as _; let _ = __buffa_src; - super::super::FileDescriptorProto { + ::core::result::Result::Ok(super::super::FileDescriptorProto { name: self.name.map(|s| s.to_string()), package: self.package.map(|s| s.to_string()), dependency: self.dependency.iter().map(|s| s.to_string()).collect(), @@ -725,27 +736,27 @@ impl<'a> ::buffa::MessageView<'a> for FileDescriptorProtoView<'a> { .message_type .iter() .map(|v| v.to_owned_from_source(__buffa_src)) - .collect(), + .collect::<::core::result::Result<_, ::buffa::DecodeError>>()?, enum_type: self .enum_type .iter() .map(|v| v.to_owned_from_source(__buffa_src)) - .collect(), + .collect::<::core::result::Result<_, ::buffa::DecodeError>>()?, service: self .service .iter() .map(|v| v.to_owned_from_source(__buffa_src)) - .collect(), + .collect::<::core::result::Result<_, ::buffa::DecodeError>>()?, extension: self .extension .iter() .map(|v| v.to_owned_from_source(__buffa_src)) - .collect(), + .collect::<::core::result::Result<_, ::buffa::DecodeError>>()?, options: match self.options.as_option() { Some(v) => { ::buffa::MessageField::< super::super::FileOptions, - >::some(v.to_owned_from_source(__buffa_src)) + >::some(v.to_owned_from_source(__buffa_src)?) } None => ::buffa::MessageField::none(), }, @@ -753,19 +764,15 @@ impl<'a> ::buffa::MessageView<'a> for FileDescriptorProtoView<'a> { Some(v) => { ::buffa::MessageField::< super::super::SourceCodeInfo, - >::some(v.to_owned_from_source(__buffa_src)) + >::some(v.to_owned_from_source(__buffa_src)?) } None => ::buffa::MessageField::none(), }, syntax: self.syntax.map(|s| s.to_string()), edition: self.edition, - __buffa_unknown_fields: self - .__buffa_unknown_fields - .to_owned() - .unwrap_or_default() - .into(), + __buffa_unknown_fields: self.__buffa_unknown_fields.to_owned()?.into(), ..::core::default::Default::default() - } + }) } } impl<'a> ::buffa::ViewEncode<'a> for FileDescriptorProtoView<'a> { @@ -1151,8 +1158,17 @@ impl FileDescriptorProtoOwnedView { self.0.reborrow() } /// Convert to the owned message type. - #[must_use] - pub fn to_owned_message(&self) -> super::super::FileDescriptorProto { + /// + /// # 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, + > { self.0.to_owned_message() } /// The underlying bytes buffer. @@ -1380,20 +1396,22 @@ pub struct DescriptorProtoView<'a> { pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, } impl<'a> DescriptorProtoView<'a> { - /// Decode from `buf`, enforcing a recursion depth limit for nested messages. + /// Decode from `buf` under the limits carried by `ctx` (recursion + /// depth and the shared unknown-field allowance). /// - /// Called by [`::buffa::MessageView::decode_view`] with [`::buffa::RECURSION_LIMIT`] - /// and by generated sub-message decode arms with `depth - 1`. + /// Called by [`::buffa::MessageView::decode_view`] with a fresh + /// default context and by generated sub-message decode arms with + /// `ctx.descend()?`. /// /// **Not part of the public API.** Named with a leading underscore to /// signal that it is for generated-code use only. #[doc(hidden)] - pub fn _decode_depth( + pub fn _decode_ctx( buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result { let mut view = Self::default(); - view._merge_into_view(buf, depth)?; + view._merge_into_view(buf, ctx)?; ::core::result::Result::Ok(view) } /// Merge fields from `buf` into this view (proto merge semantics). @@ -1407,9 +1425,9 @@ impl<'a> DescriptorProtoView<'a> { pub fn _merge_into_view( &mut self, buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result<(), ::buffa::DecodeError> { - let _ = depth; + let _ = ctx; #[allow(unused_variables)] let view = self; let mut cur: &'a [u8] = buf; @@ -1435,17 +1453,15 @@ impl<'a> DescriptorProtoView<'a> { actual: tag.wire_type() as u8, }); } - if depth == 0 { - return Err(::buffa::DecodeError::RecursionLimitExceeded); - } + let __sub_ctx = ctx.descend()?; let sub = ::buffa::types::borrow_bytes(&mut cur)?; match view.options.as_mut() { - Some(existing) => existing._merge_into_view(sub, depth - 1)?, + Some(existing) => existing._merge_into_view(sub, __sub_ctx)?, None => { view.options = ::buffa::MessageFieldView::set( - super::super::__buffa::view::MessageOptionsView::_decode_depth( + super::super::__buffa::view::MessageOptionsView::_decode_ctx( sub, - depth - 1, + __sub_ctx, )?, ); } @@ -1466,7 +1482,8 @@ impl<'a> DescriptorProtoView<'a> { view.visibility = Some(__v); } else { let __span_len = before_tag.len() - cur.len(); - view.__buffa_unknown_fields.push_raw(&before_tag[..__span_len]); + view.__buffa_unknown_fields + .push_record(before_tag, __span_len, ctx)?; } } 2u32 => { @@ -1477,15 +1494,13 @@ impl<'a> DescriptorProtoView<'a> { actual: tag.wire_type() as u8, }); } - if depth == 0 { - return Err(::buffa::DecodeError::RecursionLimitExceeded); - } + let __sub_ctx = ctx.descend()?; let sub = ::buffa::types::borrow_bytes(&mut cur)?; view.field .push( - super::super::__buffa::view::FieldDescriptorProtoView::_decode_depth( + super::super::__buffa::view::FieldDescriptorProtoView::_decode_ctx( sub, - depth - 1, + __sub_ctx, )?, ); } @@ -1497,15 +1512,13 @@ impl<'a> DescriptorProtoView<'a> { actual: tag.wire_type() as u8, }); } - if depth == 0 { - return Err(::buffa::DecodeError::RecursionLimitExceeded); - } + let __sub_ctx = ctx.descend()?; let sub = ::buffa::types::borrow_bytes(&mut cur)?; view.extension .push( - super::super::__buffa::view::FieldDescriptorProtoView::_decode_depth( + super::super::__buffa::view::FieldDescriptorProtoView::_decode_ctx( sub, - depth - 1, + __sub_ctx, )?, ); } @@ -1517,15 +1530,13 @@ impl<'a> DescriptorProtoView<'a> { actual: tag.wire_type() as u8, }); } - if depth == 0 { - return Err(::buffa::DecodeError::RecursionLimitExceeded); - } + let __sub_ctx = ctx.descend()?; let sub = ::buffa::types::borrow_bytes(&mut cur)?; view.nested_type .push( - super::super::__buffa::view::DescriptorProtoView::_decode_depth( + super::super::__buffa::view::DescriptorProtoView::_decode_ctx( sub, - depth - 1, + __sub_ctx, )?, ); } @@ -1537,15 +1548,13 @@ impl<'a> DescriptorProtoView<'a> { actual: tag.wire_type() as u8, }); } - if depth == 0 { - return Err(::buffa::DecodeError::RecursionLimitExceeded); - } + let __sub_ctx = ctx.descend()?; let sub = ::buffa::types::borrow_bytes(&mut cur)?; view.enum_type .push( - super::super::__buffa::view::EnumDescriptorProtoView::_decode_depth( + super::super::__buffa::view::EnumDescriptorProtoView::_decode_ctx( sub, - depth - 1, + __sub_ctx, )?, ); } @@ -1557,15 +1566,13 @@ impl<'a> DescriptorProtoView<'a> { actual: tag.wire_type() as u8, }); } - if depth == 0 { - return Err(::buffa::DecodeError::RecursionLimitExceeded); - } + let __sub_ctx = ctx.descend()?; let sub = ::buffa::types::borrow_bytes(&mut cur)?; view.extension_range .push( - super::super::__buffa::view::descriptor_proto::ExtensionRangeView::_decode_depth( + super::super::__buffa::view::descriptor_proto::ExtensionRangeView::_decode_ctx( sub, - depth - 1, + __sub_ctx, )?, ); } @@ -1577,15 +1584,13 @@ impl<'a> DescriptorProtoView<'a> { actual: tag.wire_type() as u8, }); } - if depth == 0 { - return Err(::buffa::DecodeError::RecursionLimitExceeded); - } + let __sub_ctx = ctx.descend()?; let sub = ::buffa::types::borrow_bytes(&mut cur)?; view.oneof_decl .push( - super::super::__buffa::view::OneofDescriptorProtoView::_decode_depth( + super::super::__buffa::view::OneofDescriptorProtoView::_decode_ctx( sub, - depth - 1, + __sub_ctx, )?, ); } @@ -1597,15 +1602,13 @@ impl<'a> DescriptorProtoView<'a> { actual: tag.wire_type() as u8, }); } - if depth == 0 { - return Err(::buffa::DecodeError::RecursionLimitExceeded); - } + let __sub_ctx = ctx.descend()?; let sub = ::buffa::types::borrow_bytes(&mut cur)?; view.reserved_range .push( - super::super::__buffa::view::descriptor_proto::ReservedRangeView::_decode_depth( + super::super::__buffa::view::descriptor_proto::ReservedRangeView::_decode_ctx( sub, - depth - 1, + __sub_ctx, )?, ); } @@ -1620,9 +1623,9 @@ impl<'a> DescriptorProtoView<'a> { view.reserved_name.push(::buffa::types::borrow_str(&mut cur)?); } _ => { - ::buffa::encoding::skip_field_depth(tag, &mut cur, depth)?; + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; let span_len = before_tag.len() - cur.len(); - view.__buffa_unknown_fields.push_raw(&before_tag[..span_len]); + view.__buffa_unknown_fields.push_record(before_tag, span_len, ctx)?; } } } @@ -1632,62 +1635,68 @@ impl<'a> DescriptorProtoView<'a> { impl<'a> ::buffa::MessageView<'a> for DescriptorProtoView<'a> { type Owned = super::super::DescriptorProto; fn decode_view(buf: &'a [u8]) -> ::core::result::Result { - Self::_decode_depth(buf, ::buffa::RECURSION_LIMIT) + let __limit = ::core::cell::Cell::new(::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT); + Self::_decode_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit), + ) } - fn decode_view_with_limit( + fn decode_view_with_ctx( buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result { - Self::_decode_depth(buf, depth) + Self::_decode_ctx(buf, ctx) } - fn to_owned_message(&self) -> super::super::DescriptorProto { + fn to_owned_message( + &self, + ) -> ::core::result::Result { self.to_owned_from_source(None) } #[allow(clippy::useless_conversion, clippy::needless_update)] fn to_owned_from_source( &self, __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, - ) -> super::super::DescriptorProto { + ) -> ::core::result::Result { #[allow(unused_imports)] use ::buffa::alloc::string::ToString as _; let _ = __buffa_src; - super::super::DescriptorProto { + ::core::result::Result::Ok(super::super::DescriptorProto { name: self.name.map(|s| s.to_string()), field: self .field .iter() .map(|v| v.to_owned_from_source(__buffa_src)) - .collect(), + .collect::<::core::result::Result<_, ::buffa::DecodeError>>()?, extension: self .extension .iter() .map(|v| v.to_owned_from_source(__buffa_src)) - .collect(), + .collect::<::core::result::Result<_, ::buffa::DecodeError>>()?, nested_type: self .nested_type .iter() .map(|v| v.to_owned_from_source(__buffa_src)) - .collect(), + .collect::<::core::result::Result<_, ::buffa::DecodeError>>()?, enum_type: self .enum_type .iter() .map(|v| v.to_owned_from_source(__buffa_src)) - .collect(), + .collect::<::core::result::Result<_, ::buffa::DecodeError>>()?, extension_range: self .extension_range .iter() .map(|v| v.to_owned_from_source(__buffa_src)) - .collect(), + .collect::<::core::result::Result<_, ::buffa::DecodeError>>()?, oneof_decl: self .oneof_decl .iter() .map(|v| v.to_owned_from_source(__buffa_src)) - .collect(), + .collect::<::core::result::Result<_, ::buffa::DecodeError>>()?, options: match self.options.as_option() { Some(v) => { ::buffa::MessageField::< super::super::MessageOptions, - >::some(v.to_owned_from_source(__buffa_src)) + >::some(v.to_owned_from_source(__buffa_src)?) } None => ::buffa::MessageField::none(), }, @@ -1695,16 +1704,12 @@ impl<'a> ::buffa::MessageView<'a> for DescriptorProtoView<'a> { .reserved_range .iter() .map(|v| v.to_owned_from_source(__buffa_src)) - .collect(), + .collect::<::core::result::Result<_, ::buffa::DecodeError>>()?, reserved_name: self.reserved_name.iter().map(|s| s.to_string()).collect(), visibility: self.visibility, - __buffa_unknown_fields: self - .__buffa_unknown_fields - .to_owned() - .unwrap_or_default() - .into(), + __buffa_unknown_fields: self.__buffa_unknown_fields.to_owned()?.into(), ..::core::default::Default::default() - } + }) } } impl<'a> ::buffa::ViewEncode<'a> for DescriptorProtoView<'a> { @@ -2043,8 +2048,14 @@ impl DescriptorProtoOwnedView { self.0.reborrow() } /// Convert to the owned message type. - #[must_use] - pub fn to_owned_message(&self) -> super::super::DescriptorProto { + /// + /// # 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 { self.0.to_owned_message() } /// The underlying bytes buffer. @@ -2208,20 +2219,22 @@ pub mod descriptor_proto { pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, } impl<'a> ExtensionRangeView<'a> { - /// Decode from `buf`, enforcing a recursion depth limit for nested messages. + /// Decode from `buf` under the limits carried by `ctx` (recursion + /// depth and the shared unknown-field allowance). /// - /// Called by [`::buffa::MessageView::decode_view`] with [`::buffa::RECURSION_LIMIT`] - /// and by generated sub-message decode arms with `depth - 1`. + /// Called by [`::buffa::MessageView::decode_view`] with a fresh + /// default context and by generated sub-message decode arms with + /// `ctx.descend()?`. /// /// **Not part of the public API.** Named with a leading underscore to /// signal that it is for generated-code use only. #[doc(hidden)] - pub fn _decode_depth( + pub fn _decode_ctx( buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result { let mut view = Self::default(); - view._merge_into_view(buf, depth)?; + view._merge_into_view(buf, ctx)?; ::core::result::Result::Ok(view) } /// Merge fields from `buf` into this view (proto merge semantics). @@ -2235,9 +2248,9 @@ pub mod descriptor_proto { pub fn _merge_into_view( &mut self, buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result<(), ::buffa::DecodeError> { - let _ = depth; + let _ = ctx; #[allow(unused_variables)] let view = self; let mut cur: &'a [u8] = buf; @@ -2275,26 +2288,25 @@ pub mod descriptor_proto { actual: tag.wire_type() as u8, }); } - if depth == 0 { - return Err(::buffa::DecodeError::RecursionLimitExceeded); - } + let __sub_ctx = ctx.descend()?; let sub = ::buffa::types::borrow_bytes(&mut cur)?; match view.options.as_mut() { - Some(existing) => existing._merge_into_view(sub, depth - 1)?, + Some(existing) => existing._merge_into_view(sub, __sub_ctx)?, None => { view.options = ::buffa::MessageFieldView::set( - super::super::super::__buffa::view::ExtensionRangeOptionsView::_decode_depth( + super::super::super::__buffa::view::ExtensionRangeOptionsView::_decode_ctx( sub, - depth - 1, + __sub_ctx, )?, ); } } } _ => { - ::buffa::encoding::skip_field_depth(tag, &mut cur, depth)?; + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; let span_len = before_tag.len() - cur.len(); - view.__buffa_unknown_fields.push_raw(&before_tag[..span_len]); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; } } } @@ -2306,45 +2318,51 @@ pub mod descriptor_proto { fn decode_view( buf: &'a [u8], ) -> ::core::result::Result { - Self::_decode_depth(buf, ::buffa::RECURSION_LIMIT) + let __limit = ::core::cell::Cell::new(::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT); + Self::_decode_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit), + ) } - fn decode_view_with_limit( + fn decode_view_with_ctx( buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result { - Self::_decode_depth(buf, depth) + Self::_decode_ctx(buf, ctx) } fn to_owned_message( &self, - ) -> super::super::super::descriptor_proto::ExtensionRange { + ) -> ::core::result::Result< + super::super::super::descriptor_proto::ExtensionRange, + ::buffa::DecodeError, + > { self.to_owned_from_source(None) } #[allow(clippy::useless_conversion, clippy::needless_update)] fn to_owned_from_source( &self, __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, - ) -> super::super::super::descriptor_proto::ExtensionRange { + ) -> ::core::result::Result< + super::super::super::descriptor_proto::ExtensionRange, + ::buffa::DecodeError, + > { #[allow(unused_imports)] use ::buffa::alloc::string::ToString as _; let _ = __buffa_src; - super::super::super::descriptor_proto::ExtensionRange { + ::core::result::Result::Ok(super::super::super::descriptor_proto::ExtensionRange { start: self.start, end: self.end, options: match self.options.as_option() { Some(v) => { ::buffa::MessageField::< super::super::super::ExtensionRangeOptions, - >::some(v.to_owned_from_source(__buffa_src)) + >::some(v.to_owned_from_source(__buffa_src)?) } None => ::buffa::MessageField::none(), }, - __buffa_unknown_fields: self - .__buffa_unknown_fields - .to_owned() - .unwrap_or_default() - .into(), + __buffa_unknown_fields: self.__buffa_unknown_fields.to_owned()?.into(), ..::core::default::Default::default() - } + }) } } impl<'a> ::buffa::ViewEncode<'a> for ExtensionRangeView<'a> { @@ -2535,10 +2553,17 @@ pub mod descriptor_proto { self.0.reborrow() } /// Convert to the owned message type. - #[must_use] + /// + /// # 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, - ) -> super::super::super::descriptor_proto::ExtensionRange { + ) -> ::core::result::Result< + super::super::super::descriptor_proto::ExtensionRange, + ::buffa::DecodeError, + > { self.0.to_owned_message() } /// The underlying bytes buffer. @@ -2623,20 +2648,22 @@ pub mod descriptor_proto { pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, } impl<'a> ReservedRangeView<'a> { - /// Decode from `buf`, enforcing a recursion depth limit for nested messages. + /// Decode from `buf` under the limits carried by `ctx` (recursion + /// depth and the shared unknown-field allowance). /// - /// Called by [`::buffa::MessageView::decode_view`] with [`::buffa::RECURSION_LIMIT`] - /// and by generated sub-message decode arms with `depth - 1`. + /// Called by [`::buffa::MessageView::decode_view`] with a fresh + /// default context and by generated sub-message decode arms with + /// `ctx.descend()?`. /// /// **Not part of the public API.** Named with a leading underscore to /// signal that it is for generated-code use only. #[doc(hidden)] - pub fn _decode_depth( + pub fn _decode_ctx( buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result { let mut view = Self::default(); - view._merge_into_view(buf, depth)?; + view._merge_into_view(buf, ctx)?; ::core::result::Result::Ok(view) } /// Merge fields from `buf` into this view (proto merge semantics). @@ -2650,9 +2677,9 @@ pub mod descriptor_proto { pub fn _merge_into_view( &mut self, buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result<(), ::buffa::DecodeError> { - let _ = depth; + let _ = ctx; #[allow(unused_variables)] let view = self; let mut cur: &'a [u8] = buf; @@ -2681,9 +2708,10 @@ pub mod descriptor_proto { view.end = Some(::buffa::types::decode_int32(&mut cur)?); } _ => { - ::buffa::encoding::skip_field_depth(tag, &mut cur, depth)?; + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; let span_len = before_tag.len() - cur.len(); - view.__buffa_unknown_fields.push_raw(&before_tag[..span_len]); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; } } } @@ -2695,37 +2723,43 @@ pub mod descriptor_proto { fn decode_view( buf: &'a [u8], ) -> ::core::result::Result { - Self::_decode_depth(buf, ::buffa::RECURSION_LIMIT) + let __limit = ::core::cell::Cell::new(::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT); + Self::_decode_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit), + ) } - fn decode_view_with_limit( + fn decode_view_with_ctx( buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result { - Self::_decode_depth(buf, depth) + Self::_decode_ctx(buf, ctx) } fn to_owned_message( &self, - ) -> super::super::super::descriptor_proto::ReservedRange { + ) -> ::core::result::Result< + super::super::super::descriptor_proto::ReservedRange, + ::buffa::DecodeError, + > { self.to_owned_from_source(None) } #[allow(clippy::useless_conversion, clippy::needless_update)] fn to_owned_from_source( &self, __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, - ) -> super::super::super::descriptor_proto::ReservedRange { + ) -> ::core::result::Result< + super::super::super::descriptor_proto::ReservedRange, + ::buffa::DecodeError, + > { #[allow(unused_imports)] use ::buffa::alloc::string::ToString as _; let _ = __buffa_src; - super::super::super::descriptor_proto::ReservedRange { + ::core::result::Result::Ok(super::super::super::descriptor_proto::ReservedRange { start: self.start, end: self.end, - __buffa_unknown_fields: self - .__buffa_unknown_fields - .to_owned() - .unwrap_or_default() - .into(), + __buffa_unknown_fields: self.__buffa_unknown_fields.to_owned()?.into(), ..::core::default::Default::default() - } + }) } } impl<'a> ::buffa::ViewEncode<'a> for ReservedRangeView<'a> { @@ -2894,10 +2928,17 @@ pub mod descriptor_proto { self.0.reborrow() } /// Convert to the owned message type. - #[must_use] + /// + /// # 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, - ) -> super::super::super::descriptor_proto::ReservedRange { + ) -> ::core::result::Result< + super::super::super::descriptor_proto::ReservedRange, + ::buffa::DecodeError, + > { self.0.to_owned_message() } /// The underlying bytes buffer. @@ -2993,20 +3034,22 @@ pub struct ExtensionRangeOptionsView<'a> { pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, } impl<'a> ExtensionRangeOptionsView<'a> { - /// Decode from `buf`, enforcing a recursion depth limit for nested messages. + /// Decode from `buf` under the limits carried by `ctx` (recursion + /// depth and the shared unknown-field allowance). /// - /// Called by [`::buffa::MessageView::decode_view`] with [`::buffa::RECURSION_LIMIT`] - /// and by generated sub-message decode arms with `depth - 1`. + /// Called by [`::buffa::MessageView::decode_view`] with a fresh + /// default context and by generated sub-message decode arms with + /// `ctx.descend()?`. /// /// **Not part of the public API.** Named with a leading underscore to /// signal that it is for generated-code use only. #[doc(hidden)] - pub fn _decode_depth( + pub fn _decode_ctx( buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result { let mut view = Self::default(); - view._merge_into_view(buf, depth)?; + view._merge_into_view(buf, ctx)?; ::core::result::Result::Ok(view) } /// Merge fields from `buf` into this view (proto merge semantics). @@ -3020,9 +3063,9 @@ impl<'a> ExtensionRangeOptionsView<'a> { pub fn _merge_into_view( &mut self, buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result<(), ::buffa::DecodeError> { - let _ = depth; + let _ = ctx; #[allow(unused_variables)] let view = self; let mut cur: &'a [u8] = buf; @@ -3038,17 +3081,15 @@ impl<'a> ExtensionRangeOptionsView<'a> { actual: tag.wire_type() as u8, }); } - if depth == 0 { - return Err(::buffa::DecodeError::RecursionLimitExceeded); - } + let __sub_ctx = ctx.descend()?; let sub = ::buffa::types::borrow_bytes(&mut cur)?; match view.features.as_mut() { - Some(existing) => existing._merge_into_view(sub, depth - 1)?, + Some(existing) => existing._merge_into_view(sub, __sub_ctx)?, None => { view.features = ::buffa::MessageFieldView::set( - super::super::__buffa::view::FeatureSetView::_decode_depth( + super::super::__buffa::view::FeatureSetView::_decode_ctx( sub, - depth - 1, + __sub_ctx, )?, ); } @@ -3069,7 +3110,8 @@ impl<'a> ExtensionRangeOptionsView<'a> { view.verification = Some(__v); } else { let __span_len = before_tag.len() - cur.len(); - view.__buffa_unknown_fields.push_raw(&before_tag[..__span_len]); + view.__buffa_unknown_fields + .push_record(before_tag, __span_len, ctx)?; } } 999u32 => { @@ -3080,15 +3122,13 @@ impl<'a> ExtensionRangeOptionsView<'a> { actual: tag.wire_type() as u8, }); } - if depth == 0 { - return Err(::buffa::DecodeError::RecursionLimitExceeded); - } + let __sub_ctx = ctx.descend()?; let sub = ::buffa::types::borrow_bytes(&mut cur)?; view.uninterpreted_option .push( - super::super::__buffa::view::UninterpretedOptionView::_decode_depth( + super::super::__buffa::view::UninterpretedOptionView::_decode_ctx( sub, - depth - 1, + __sub_ctx, )?, ); } @@ -3100,22 +3140,20 @@ impl<'a> ExtensionRangeOptionsView<'a> { actual: tag.wire_type() as u8, }); } - if depth == 0 { - return Err(::buffa::DecodeError::RecursionLimitExceeded); - } + let __sub_ctx = ctx.descend()?; let sub = ::buffa::types::borrow_bytes(&mut cur)?; view.declaration .push( - super::super::__buffa::view::extension_range_options::DeclarationView::_decode_depth( + super::super::__buffa::view::extension_range_options::DeclarationView::_decode_ctx( sub, - depth - 1, + __sub_ctx, )?, ); } _ => { - ::buffa::encoding::skip_field_depth(tag, &mut cur, depth)?; + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; let span_len = before_tag.len() - cur.len(); - view.__buffa_unknown_fields.push_raw(&before_tag[..span_len]); + view.__buffa_unknown_fields.push_record(before_tag, span_len, ctx)?; } } } @@ -3125,52 +3163,60 @@ impl<'a> ExtensionRangeOptionsView<'a> { impl<'a> ::buffa::MessageView<'a> for ExtensionRangeOptionsView<'a> { type Owned = super::super::ExtensionRangeOptions; fn decode_view(buf: &'a [u8]) -> ::core::result::Result { - Self::_decode_depth(buf, ::buffa::RECURSION_LIMIT) + let __limit = ::core::cell::Cell::new(::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT); + Self::_decode_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit), + ) } - fn decode_view_with_limit( + fn decode_view_with_ctx( buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result { - Self::_decode_depth(buf, depth) + Self::_decode_ctx(buf, ctx) } - fn to_owned_message(&self) -> super::super::ExtensionRangeOptions { + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::ExtensionRangeOptions, + ::buffa::DecodeError, + > { self.to_owned_from_source(None) } #[allow(clippy::useless_conversion, clippy::needless_update)] fn to_owned_from_source( &self, __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, - ) -> super::super::ExtensionRangeOptions { + ) -> ::core::result::Result< + super::super::ExtensionRangeOptions, + ::buffa::DecodeError, + > { #[allow(unused_imports)] use ::buffa::alloc::string::ToString as _; let _ = __buffa_src; - super::super::ExtensionRangeOptions { + ::core::result::Result::Ok(super::super::ExtensionRangeOptions { uninterpreted_option: self .uninterpreted_option .iter() .map(|v| v.to_owned_from_source(__buffa_src)) - .collect(), + .collect::<::core::result::Result<_, ::buffa::DecodeError>>()?, declaration: self .declaration .iter() .map(|v| v.to_owned_from_source(__buffa_src)) - .collect(), + .collect::<::core::result::Result<_, ::buffa::DecodeError>>()?, features: match self.features.as_option() { Some(v) => { ::buffa::MessageField::< super::super::FeatureSet, - >::some(v.to_owned_from_source(__buffa_src)) + >::some(v.to_owned_from_source(__buffa_src)?) } None => ::buffa::MessageField::none(), }, verification: self.verification, - __buffa_unknown_fields: self - .__buffa_unknown_fields - .to_owned() - .unwrap_or_default() - .into(), + __buffa_unknown_fields: self.__buffa_unknown_fields.to_owned()?.into(), ..::core::default::Default::default() - } + }) } } impl<'a> ::buffa::ViewEncode<'a> for ExtensionRangeOptionsView<'a> { @@ -3383,8 +3429,17 @@ impl ExtensionRangeOptionsOwnedView { self.0.reborrow() } /// Convert to the owned message type. - #[must_use] - pub fn to_owned_message(&self) -> super::super::ExtensionRangeOptions { + /// + /// # 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, + > { self.0.to_owned_message() } /// The underlying bytes buffer. @@ -3511,20 +3566,22 @@ pub mod extension_range_options { pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, } impl<'a> DeclarationView<'a> { - /// Decode from `buf`, enforcing a recursion depth limit for nested messages. + /// Decode from `buf` under the limits carried by `ctx` (recursion + /// depth and the shared unknown-field allowance). /// - /// Called by [`::buffa::MessageView::decode_view`] with [`::buffa::RECURSION_LIMIT`] - /// and by generated sub-message decode arms with `depth - 1`. + /// Called by [`::buffa::MessageView::decode_view`] with a fresh + /// default context and by generated sub-message decode arms with + /// `ctx.descend()?`. /// /// **Not part of the public API.** Named with a leading underscore to /// signal that it is for generated-code use only. #[doc(hidden)] - pub fn _decode_depth( + pub fn _decode_ctx( buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result { let mut view = Self::default(); - view._merge_into_view(buf, depth)?; + view._merge_into_view(buf, ctx)?; ::core::result::Result::Ok(view) } /// Merge fields from `buf` into this view (proto merge semantics). @@ -3538,9 +3595,9 @@ pub mod extension_range_options { pub fn _merge_into_view( &mut self, buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result<(), ::buffa::DecodeError> { - let _ = depth; + let _ = ctx; #[allow(unused_variables)] let view = self; let mut cur: &'a [u8] = buf; @@ -3603,9 +3660,10 @@ pub mod extension_range_options { view.repeated = Some(::buffa::types::decode_bool(&mut cur)?); } _ => { - ::buffa::encoding::skip_field_depth(tag, &mut cur, depth)?; + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; let span_len = before_tag.len() - cur.len(); - view.__buffa_unknown_fields.push_raw(&before_tag[..span_len]); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; } } } @@ -3617,40 +3675,46 @@ pub mod extension_range_options { fn decode_view( buf: &'a [u8], ) -> ::core::result::Result { - Self::_decode_depth(buf, ::buffa::RECURSION_LIMIT) + let __limit = ::core::cell::Cell::new(::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT); + Self::_decode_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit), + ) } - fn decode_view_with_limit( + fn decode_view_with_ctx( buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result { - Self::_decode_depth(buf, depth) + Self::_decode_ctx(buf, ctx) } fn to_owned_message( &self, - ) -> super::super::super::extension_range_options::Declaration { + ) -> ::core::result::Result< + super::super::super::extension_range_options::Declaration, + ::buffa::DecodeError, + > { self.to_owned_from_source(None) } #[allow(clippy::useless_conversion, clippy::needless_update)] fn to_owned_from_source( &self, __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, - ) -> super::super::super::extension_range_options::Declaration { + ) -> ::core::result::Result< + super::super::super::extension_range_options::Declaration, + ::buffa::DecodeError, + > { #[allow(unused_imports)] use ::buffa::alloc::string::ToString as _; let _ = __buffa_src; - super::super::super::extension_range_options::Declaration { + ::core::result::Result::Ok(super::super::super::extension_range_options::Declaration { number: self.number, full_name: self.full_name.map(|s| s.to_string()), r#type: self.r#type.map(|s| s.to_string()), reserved: self.reserved, repeated: self.repeated, - __buffa_unknown_fields: self - .__buffa_unknown_fields - .to_owned() - .unwrap_or_default() - .into(), + __buffa_unknown_fields: self.__buffa_unknown_fields.to_owned()?.into(), ..::core::default::Default::default() - } + }) } } impl<'a> ::buffa::ViewEncode<'a> for DeclarationView<'a> { @@ -3849,10 +3913,17 @@ pub mod extension_range_options { self.0.reborrow() } /// Convert to the owned message type. - #[must_use] + /// + /// # 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, - ) -> super::super::super::extension_range_options::Declaration { + ) -> ::core::result::Result< + super::super::super::extension_range_options::Declaration, + ::buffa::DecodeError, + > { self.0.to_owned_message() } /// The underlying bytes buffer. @@ -4017,20 +4088,22 @@ pub struct FieldDescriptorProtoView<'a> { pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, } impl<'a> FieldDescriptorProtoView<'a> { - /// Decode from `buf`, enforcing a recursion depth limit for nested messages. + /// Decode from `buf` under the limits carried by `ctx` (recursion + /// depth and the shared unknown-field allowance). /// - /// Called by [`::buffa::MessageView::decode_view`] with [`::buffa::RECURSION_LIMIT`] - /// and by generated sub-message decode arms with `depth - 1`. + /// Called by [`::buffa::MessageView::decode_view`] with a fresh + /// default context and by generated sub-message decode arms with + /// `ctx.descend()?`. /// /// **Not part of the public API.** Named with a leading underscore to /// signal that it is for generated-code use only. #[doc(hidden)] - pub fn _decode_depth( + pub fn _decode_ctx( buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result { let mut view = Self::default(); - view._merge_into_view(buf, depth)?; + view._merge_into_view(buf, ctx)?; ::core::result::Result::Ok(view) } /// Merge fields from `buf` into this view (proto merge semantics). @@ -4044,9 +4117,9 @@ impl<'a> FieldDescriptorProtoView<'a> { pub fn _merge_into_view( &mut self, buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result<(), ::buffa::DecodeError> { - let _ = depth; + let _ = ctx; #[allow(unused_variables)] let view = self; let mut cur: &'a [u8] = buf; @@ -4089,7 +4162,8 @@ impl<'a> FieldDescriptorProtoView<'a> { view.label = Some(__v); } else { let __span_len = before_tag.len() - cur.len(); - view.__buffa_unknown_fields.push_raw(&before_tag[..__span_len]); + view.__buffa_unknown_fields + .push_record(before_tag, __span_len, ctx)?; } } 5u32 => { @@ -4107,7 +4181,8 @@ impl<'a> FieldDescriptorProtoView<'a> { view.r#type = Some(__v); } else { let __span_len = before_tag.len() - cur.len(); - view.__buffa_unknown_fields.push_raw(&before_tag[..__span_len]); + view.__buffa_unknown_fields + .push_record(before_tag, __span_len, ctx)?; } } 6u32 => { @@ -4168,17 +4243,15 @@ impl<'a> FieldDescriptorProtoView<'a> { actual: tag.wire_type() as u8, }); } - if depth == 0 { - return Err(::buffa::DecodeError::RecursionLimitExceeded); - } + let __sub_ctx = ctx.descend()?; let sub = ::buffa::types::borrow_bytes(&mut cur)?; match view.options.as_mut() { - Some(existing) => existing._merge_into_view(sub, depth - 1)?, + Some(existing) => existing._merge_into_view(sub, __sub_ctx)?, None => { view.options = ::buffa::MessageFieldView::set( - super::super::__buffa::view::FieldOptionsView::_decode_depth( + super::super::__buffa::view::FieldOptionsView::_decode_ctx( sub, - depth - 1, + __sub_ctx, )?, ); } @@ -4195,9 +4268,9 @@ impl<'a> FieldDescriptorProtoView<'a> { view.proto3_optional = Some(::buffa::types::decode_bool(&mut cur)?); } _ => { - ::buffa::encoding::skip_field_depth(tag, &mut cur, depth)?; + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; let span_len = before_tag.len() - cur.len(); - view.__buffa_unknown_fields.push_raw(&before_tag[..span_len]); + view.__buffa_unknown_fields.push_record(before_tag, span_len, ctx)?; } } } @@ -4207,26 +4280,38 @@ impl<'a> FieldDescriptorProtoView<'a> { impl<'a> ::buffa::MessageView<'a> for FieldDescriptorProtoView<'a> { type Owned = super::super::FieldDescriptorProto; fn decode_view(buf: &'a [u8]) -> ::core::result::Result { - Self::_decode_depth(buf, ::buffa::RECURSION_LIMIT) + let __limit = ::core::cell::Cell::new(::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT); + Self::_decode_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit), + ) } - fn decode_view_with_limit( + fn decode_view_with_ctx( buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result { - Self::_decode_depth(buf, depth) + Self::_decode_ctx(buf, ctx) } - fn to_owned_message(&self) -> super::super::FieldDescriptorProto { + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::FieldDescriptorProto, + ::buffa::DecodeError, + > { self.to_owned_from_source(None) } #[allow(clippy::useless_conversion, clippy::needless_update)] fn to_owned_from_source( &self, __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, - ) -> super::super::FieldDescriptorProto { + ) -> ::core::result::Result< + super::super::FieldDescriptorProto, + ::buffa::DecodeError, + > { #[allow(unused_imports)] use ::buffa::alloc::string::ToString as _; let _ = __buffa_src; - super::super::FieldDescriptorProto { + ::core::result::Result::Ok(super::super::FieldDescriptorProto { name: self.name.map(|s| s.to_string()), number: self.number, label: self.label, @@ -4240,18 +4325,14 @@ impl<'a> ::buffa::MessageView<'a> for FieldDescriptorProtoView<'a> { Some(v) => { ::buffa::MessageField::< super::super::FieldOptions, - >::some(v.to_owned_from_source(__buffa_src)) + >::some(v.to_owned_from_source(__buffa_src)?) } None => ::buffa::MessageField::none(), }, proto3_optional: self.proto3_optional, - __buffa_unknown_fields: self - .__buffa_unknown_fields - .to_owned() - .unwrap_or_default() - .into(), + __buffa_unknown_fields: self.__buffa_unknown_fields.to_owned()?.into(), ..::core::default::Default::default() - } + }) } } impl<'a> ::buffa::ViewEncode<'a> for FieldDescriptorProtoView<'a> { @@ -4565,8 +4646,17 @@ impl FieldDescriptorProtoOwnedView { self.0.reborrow() } /// Convert to the owned message type. - #[must_use] - pub fn to_owned_message(&self) -> super::super::FieldDescriptorProto { + /// + /// # 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, + > { self.0.to_owned_message() } /// The underlying bytes buffer. @@ -4731,20 +4821,22 @@ pub struct OneofDescriptorProtoView<'a> { pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, } impl<'a> OneofDescriptorProtoView<'a> { - /// Decode from `buf`, enforcing a recursion depth limit for nested messages. + /// Decode from `buf` under the limits carried by `ctx` (recursion + /// depth and the shared unknown-field allowance). /// - /// Called by [`::buffa::MessageView::decode_view`] with [`::buffa::RECURSION_LIMIT`] - /// and by generated sub-message decode arms with `depth - 1`. + /// Called by [`::buffa::MessageView::decode_view`] with a fresh + /// default context and by generated sub-message decode arms with + /// `ctx.descend()?`. /// /// **Not part of the public API.** Named with a leading underscore to /// signal that it is for generated-code use only. #[doc(hidden)] - pub fn _decode_depth( + pub fn _decode_ctx( buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result { let mut view = Self::default(); - view._merge_into_view(buf, depth)?; + view._merge_into_view(buf, ctx)?; ::core::result::Result::Ok(view) } /// Merge fields from `buf` into this view (proto merge semantics). @@ -4758,9 +4850,9 @@ impl<'a> OneofDescriptorProtoView<'a> { pub fn _merge_into_view( &mut self, buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result<(), ::buffa::DecodeError> { - let _ = depth; + let _ = ctx; #[allow(unused_variables)] let view = self; let mut cur: &'a [u8] = buf; @@ -4786,26 +4878,24 @@ impl<'a> OneofDescriptorProtoView<'a> { actual: tag.wire_type() as u8, }); } - if depth == 0 { - return Err(::buffa::DecodeError::RecursionLimitExceeded); - } + let __sub_ctx = ctx.descend()?; let sub = ::buffa::types::borrow_bytes(&mut cur)?; match view.options.as_mut() { - Some(existing) => existing._merge_into_view(sub, depth - 1)?, + Some(existing) => existing._merge_into_view(sub, __sub_ctx)?, None => { view.options = ::buffa::MessageFieldView::set( - super::super::__buffa::view::OneofOptionsView::_decode_depth( + super::super::__buffa::view::OneofOptionsView::_decode_ctx( sub, - depth - 1, + __sub_ctx, )?, ); } } } _ => { - ::buffa::encoding::skip_field_depth(tag, &mut cur, depth)?; + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; let span_len = before_tag.len() - cur.len(); - view.__buffa_unknown_fields.push_raw(&before_tag[..span_len]); + view.__buffa_unknown_fields.push_record(before_tag, span_len, ctx)?; } } } @@ -4815,42 +4905,50 @@ impl<'a> OneofDescriptorProtoView<'a> { impl<'a> ::buffa::MessageView<'a> for OneofDescriptorProtoView<'a> { type Owned = super::super::OneofDescriptorProto; fn decode_view(buf: &'a [u8]) -> ::core::result::Result { - Self::_decode_depth(buf, ::buffa::RECURSION_LIMIT) + let __limit = ::core::cell::Cell::new(::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT); + Self::_decode_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit), + ) } - fn decode_view_with_limit( + fn decode_view_with_ctx( buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result { - Self::_decode_depth(buf, depth) + Self::_decode_ctx(buf, ctx) } - fn to_owned_message(&self) -> super::super::OneofDescriptorProto { + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::OneofDescriptorProto, + ::buffa::DecodeError, + > { self.to_owned_from_source(None) } #[allow(clippy::useless_conversion, clippy::needless_update)] fn to_owned_from_source( &self, __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, - ) -> super::super::OneofDescriptorProto { + ) -> ::core::result::Result< + super::super::OneofDescriptorProto, + ::buffa::DecodeError, + > { #[allow(unused_imports)] use ::buffa::alloc::string::ToString as _; let _ = __buffa_src; - super::super::OneofDescriptorProto { + ::core::result::Result::Ok(super::super::OneofDescriptorProto { name: self.name.map(|s| s.to_string()), options: match self.options.as_option() { Some(v) => { ::buffa::MessageField::< super::super::OneofOptions, - >::some(v.to_owned_from_source(__buffa_src)) + >::some(v.to_owned_from_source(__buffa_src)?) } None => ::buffa::MessageField::none(), }, - __buffa_unknown_fields: self - .__buffa_unknown_fields - .to_owned() - .unwrap_or_default() - .into(), + __buffa_unknown_fields: self.__buffa_unknown_fields.to_owned()?.into(), ..::core::default::Default::default() - } + }) } } impl<'a> ::buffa::ViewEncode<'a> for OneofDescriptorProtoView<'a> { @@ -5017,8 +5115,17 @@ impl OneofDescriptorProtoOwnedView { self.0.reborrow() } /// Convert to the owned message type. - #[must_use] - pub fn to_owned_message(&self) -> super::super::OneofDescriptorProto { + /// + /// # 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, + > { self.0.to_owned_message() } /// The underlying bytes buffer. @@ -5110,20 +5217,22 @@ pub struct EnumDescriptorProtoView<'a> { pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, } impl<'a> EnumDescriptorProtoView<'a> { - /// Decode from `buf`, enforcing a recursion depth limit for nested messages. + /// Decode from `buf` under the limits carried by `ctx` (recursion + /// depth and the shared unknown-field allowance). /// - /// Called by [`::buffa::MessageView::decode_view`] with [`::buffa::RECURSION_LIMIT`] - /// and by generated sub-message decode arms with `depth - 1`. + /// Called by [`::buffa::MessageView::decode_view`] with a fresh + /// default context and by generated sub-message decode arms with + /// `ctx.descend()?`. /// /// **Not part of the public API.** Named with a leading underscore to /// signal that it is for generated-code use only. #[doc(hidden)] - pub fn _decode_depth( + pub fn _decode_ctx( buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result { let mut view = Self::default(); - view._merge_into_view(buf, depth)?; + view._merge_into_view(buf, ctx)?; ::core::result::Result::Ok(view) } /// Merge fields from `buf` into this view (proto merge semantics). @@ -5137,9 +5246,9 @@ impl<'a> EnumDescriptorProtoView<'a> { pub fn _merge_into_view( &mut self, buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result<(), ::buffa::DecodeError> { - let _ = depth; + let _ = ctx; #[allow(unused_variables)] let view = self; let mut cur: &'a [u8] = buf; @@ -5165,17 +5274,15 @@ impl<'a> EnumDescriptorProtoView<'a> { actual: tag.wire_type() as u8, }); } - if depth == 0 { - return Err(::buffa::DecodeError::RecursionLimitExceeded); - } + let __sub_ctx = ctx.descend()?; let sub = ::buffa::types::borrow_bytes(&mut cur)?; match view.options.as_mut() { - Some(existing) => existing._merge_into_view(sub, depth - 1)?, + Some(existing) => existing._merge_into_view(sub, __sub_ctx)?, None => { view.options = ::buffa::MessageFieldView::set( - super::super::__buffa::view::EnumOptionsView::_decode_depth( + super::super::__buffa::view::EnumOptionsView::_decode_ctx( sub, - depth - 1, + __sub_ctx, )?, ); } @@ -5196,7 +5303,8 @@ impl<'a> EnumDescriptorProtoView<'a> { view.visibility = Some(__v); } else { let __span_len = before_tag.len() - cur.len(); - view.__buffa_unknown_fields.push_raw(&before_tag[..__span_len]); + view.__buffa_unknown_fields + .push_record(before_tag, __span_len, ctx)?; } } 2u32 => { @@ -5207,15 +5315,13 @@ impl<'a> EnumDescriptorProtoView<'a> { actual: tag.wire_type() as u8, }); } - if depth == 0 { - return Err(::buffa::DecodeError::RecursionLimitExceeded); - } + let __sub_ctx = ctx.descend()?; let sub = ::buffa::types::borrow_bytes(&mut cur)?; view.value .push( - super::super::__buffa::view::EnumValueDescriptorProtoView::_decode_depth( + super::super::__buffa::view::EnumValueDescriptorProtoView::_decode_ctx( sub, - depth - 1, + __sub_ctx, )?, ); } @@ -5227,15 +5333,13 @@ impl<'a> EnumDescriptorProtoView<'a> { actual: tag.wire_type() as u8, }); } - if depth == 0 { - return Err(::buffa::DecodeError::RecursionLimitExceeded); - } + let __sub_ctx = ctx.descend()?; let sub = ::buffa::types::borrow_bytes(&mut cur)?; view.reserved_range .push( - super::super::__buffa::view::enum_descriptor_proto::EnumReservedRangeView::_decode_depth( + super::super::__buffa::view::enum_descriptor_proto::EnumReservedRangeView::_decode_ctx( sub, - depth - 1, + __sub_ctx, )?, ); } @@ -5250,9 +5354,9 @@ impl<'a> EnumDescriptorProtoView<'a> { view.reserved_name.push(::buffa::types::borrow_str(&mut cur)?); } _ => { - ::buffa::encoding::skip_field_depth(tag, &mut cur, depth)?; + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; let span_len = before_tag.len() - cur.len(); - view.__buffa_unknown_fields.push_raw(&before_tag[..span_len]); + view.__buffa_unknown_fields.push_record(before_tag, span_len, ctx)?; } } } @@ -5262,37 +5366,49 @@ impl<'a> EnumDescriptorProtoView<'a> { impl<'a> ::buffa::MessageView<'a> for EnumDescriptorProtoView<'a> { type Owned = super::super::EnumDescriptorProto; fn decode_view(buf: &'a [u8]) -> ::core::result::Result { - Self::_decode_depth(buf, ::buffa::RECURSION_LIMIT) + let __limit = ::core::cell::Cell::new(::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT); + Self::_decode_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit), + ) } - fn decode_view_with_limit( + fn decode_view_with_ctx( buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result { - Self::_decode_depth(buf, depth) + Self::_decode_ctx(buf, ctx) } - fn to_owned_message(&self) -> super::super::EnumDescriptorProto { + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::EnumDescriptorProto, + ::buffa::DecodeError, + > { self.to_owned_from_source(None) } #[allow(clippy::useless_conversion, clippy::needless_update)] fn to_owned_from_source( &self, __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, - ) -> super::super::EnumDescriptorProto { + ) -> ::core::result::Result< + super::super::EnumDescriptorProto, + ::buffa::DecodeError, + > { #[allow(unused_imports)] use ::buffa::alloc::string::ToString as _; let _ = __buffa_src; - super::super::EnumDescriptorProto { + ::core::result::Result::Ok(super::super::EnumDescriptorProto { name: self.name.map(|s| s.to_string()), value: self .value .iter() .map(|v| v.to_owned_from_source(__buffa_src)) - .collect(), + .collect::<::core::result::Result<_, ::buffa::DecodeError>>()?, options: match self.options.as_option() { Some(v) => { ::buffa::MessageField::< super::super::EnumOptions, - >::some(v.to_owned_from_source(__buffa_src)) + >::some(v.to_owned_from_source(__buffa_src)?) } None => ::buffa::MessageField::none(), }, @@ -5300,16 +5416,12 @@ impl<'a> ::buffa::MessageView<'a> for EnumDescriptorProtoView<'a> { .reserved_range .iter() .map(|v| v.to_owned_from_source(__buffa_src)) - .collect(), + .collect::<::core::result::Result<_, ::buffa::DecodeError>>()?, reserved_name: self.reserved_name.iter().map(|s| s.to_string()).collect(), visibility: self.visibility, - __buffa_unknown_fields: self - .__buffa_unknown_fields - .to_owned() - .unwrap_or_default() - .into(), + __buffa_unknown_fields: self.__buffa_unknown_fields.to_owned()?.into(), ..::core::default::Default::default() - } + }) } } impl<'a> ::buffa::ViewEncode<'a> for EnumDescriptorProtoView<'a> { @@ -5550,8 +5662,17 @@ impl EnumDescriptorProtoOwnedView { self.0.reborrow() } /// Convert to the owned message type. - #[must_use] - pub fn to_owned_message(&self) -> super::super::EnumDescriptorProto { + /// + /// # 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, + > { self.0.to_owned_message() } /// The underlying bytes buffer. @@ -5669,20 +5790,22 @@ pub mod enum_descriptor_proto { pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, } impl<'a> EnumReservedRangeView<'a> { - /// Decode from `buf`, enforcing a recursion depth limit for nested messages. + /// Decode from `buf` under the limits carried by `ctx` (recursion + /// depth and the shared unknown-field allowance). /// - /// Called by [`::buffa::MessageView::decode_view`] with [`::buffa::RECURSION_LIMIT`] - /// and by generated sub-message decode arms with `depth - 1`. + /// Called by [`::buffa::MessageView::decode_view`] with a fresh + /// default context and by generated sub-message decode arms with + /// `ctx.descend()?`. /// /// **Not part of the public API.** Named with a leading underscore to /// signal that it is for generated-code use only. #[doc(hidden)] - pub fn _decode_depth( + pub fn _decode_ctx( buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result { let mut view = Self::default(); - view._merge_into_view(buf, depth)?; + view._merge_into_view(buf, ctx)?; ::core::result::Result::Ok(view) } /// Merge fields from `buf` into this view (proto merge semantics). @@ -5696,9 +5819,9 @@ pub mod enum_descriptor_proto { pub fn _merge_into_view( &mut self, buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result<(), ::buffa::DecodeError> { - let _ = depth; + let _ = ctx; #[allow(unused_variables)] let view = self; let mut cur: &'a [u8] = buf; @@ -5727,9 +5850,10 @@ pub mod enum_descriptor_proto { view.end = Some(::buffa::types::decode_int32(&mut cur)?); } _ => { - ::buffa::encoding::skip_field_depth(tag, &mut cur, depth)?; + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; let span_len = before_tag.len() - cur.len(); - view.__buffa_unknown_fields.push_raw(&before_tag[..span_len]); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; } } } @@ -5741,37 +5865,43 @@ pub mod enum_descriptor_proto { fn decode_view( buf: &'a [u8], ) -> ::core::result::Result { - Self::_decode_depth(buf, ::buffa::RECURSION_LIMIT) + let __limit = ::core::cell::Cell::new(::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT); + Self::_decode_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit), + ) } - fn decode_view_with_limit( + fn decode_view_with_ctx( buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result { - Self::_decode_depth(buf, depth) + Self::_decode_ctx(buf, ctx) } fn to_owned_message( &self, - ) -> super::super::super::enum_descriptor_proto::EnumReservedRange { + ) -> ::core::result::Result< + super::super::super::enum_descriptor_proto::EnumReservedRange, + ::buffa::DecodeError, + > { self.to_owned_from_source(None) } #[allow(clippy::useless_conversion, clippy::needless_update)] fn to_owned_from_source( &self, __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, - ) -> super::super::super::enum_descriptor_proto::EnumReservedRange { + ) -> ::core::result::Result< + super::super::super::enum_descriptor_proto::EnumReservedRange, + ::buffa::DecodeError, + > { #[allow(unused_imports)] use ::buffa::alloc::string::ToString as _; let _ = __buffa_src; - super::super::super::enum_descriptor_proto::EnumReservedRange { + ::core::result::Result::Ok(super::super::super::enum_descriptor_proto::EnumReservedRange { start: self.start, end: self.end, - __buffa_unknown_fields: self - .__buffa_unknown_fields - .to_owned() - .unwrap_or_default() - .into(), + __buffa_unknown_fields: self.__buffa_unknown_fields.to_owned()?.into(), ..::core::default::Default::default() - } + }) } } impl<'a> ::buffa::ViewEncode<'a> for EnumReservedRangeView<'a> { @@ -5942,10 +6072,17 @@ pub mod enum_descriptor_proto { self.0.reborrow() } /// Convert to the owned message type. - #[must_use] + /// + /// # 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, - ) -> super::super::super::enum_descriptor_proto::EnumReservedRange { + ) -> ::core::result::Result< + super::super::super::enum_descriptor_proto::EnumReservedRange, + ::buffa::DecodeError, + > { self.0.to_owned_message() } /// The underlying bytes buffer. @@ -6020,20 +6157,22 @@ pub struct EnumValueDescriptorProtoView<'a> { pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, } impl<'a> EnumValueDescriptorProtoView<'a> { - /// Decode from `buf`, enforcing a recursion depth limit for nested messages. + /// Decode from `buf` under the limits carried by `ctx` (recursion + /// depth and the shared unknown-field allowance). /// - /// Called by [`::buffa::MessageView::decode_view`] with [`::buffa::RECURSION_LIMIT`] - /// and by generated sub-message decode arms with `depth - 1`. + /// Called by [`::buffa::MessageView::decode_view`] with a fresh + /// default context and by generated sub-message decode arms with + /// `ctx.descend()?`. /// /// **Not part of the public API.** Named with a leading underscore to /// signal that it is for generated-code use only. #[doc(hidden)] - pub fn _decode_depth( + pub fn _decode_ctx( buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result { let mut view = Self::default(); - view._merge_into_view(buf, depth)?; + view._merge_into_view(buf, ctx)?; ::core::result::Result::Ok(view) } /// Merge fields from `buf` into this view (proto merge semantics). @@ -6047,9 +6186,9 @@ impl<'a> EnumValueDescriptorProtoView<'a> { pub fn _merge_into_view( &mut self, buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result<(), ::buffa::DecodeError> { - let _ = depth; + let _ = ctx; #[allow(unused_variables)] let view = self; let mut cur: &'a [u8] = buf; @@ -6085,26 +6224,24 @@ impl<'a> EnumValueDescriptorProtoView<'a> { actual: tag.wire_type() as u8, }); } - if depth == 0 { - return Err(::buffa::DecodeError::RecursionLimitExceeded); - } + let __sub_ctx = ctx.descend()?; let sub = ::buffa::types::borrow_bytes(&mut cur)?; match view.options.as_mut() { - Some(existing) => existing._merge_into_view(sub, depth - 1)?, + Some(existing) => existing._merge_into_view(sub, __sub_ctx)?, None => { view.options = ::buffa::MessageFieldView::set( - super::super::__buffa::view::EnumValueOptionsView::_decode_depth( + super::super::__buffa::view::EnumValueOptionsView::_decode_ctx( sub, - depth - 1, + __sub_ctx, )?, ); } } } _ => { - ::buffa::encoding::skip_field_depth(tag, &mut cur, depth)?; + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; let span_len = before_tag.len() - cur.len(); - view.__buffa_unknown_fields.push_raw(&before_tag[..span_len]); + view.__buffa_unknown_fields.push_record(before_tag, span_len, ctx)?; } } } @@ -6114,43 +6251,51 @@ impl<'a> EnumValueDescriptorProtoView<'a> { impl<'a> ::buffa::MessageView<'a> for EnumValueDescriptorProtoView<'a> { type Owned = super::super::EnumValueDescriptorProto; fn decode_view(buf: &'a [u8]) -> ::core::result::Result { - Self::_decode_depth(buf, ::buffa::RECURSION_LIMIT) + let __limit = ::core::cell::Cell::new(::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT); + Self::_decode_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit), + ) } - fn decode_view_with_limit( + fn decode_view_with_ctx( buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result { - Self::_decode_depth(buf, depth) + Self::_decode_ctx(buf, ctx) } - fn to_owned_message(&self) -> super::super::EnumValueDescriptorProto { + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::EnumValueDescriptorProto, + ::buffa::DecodeError, + > { self.to_owned_from_source(None) } #[allow(clippy::useless_conversion, clippy::needless_update)] fn to_owned_from_source( &self, __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, - ) -> super::super::EnumValueDescriptorProto { + ) -> ::core::result::Result< + super::super::EnumValueDescriptorProto, + ::buffa::DecodeError, + > { #[allow(unused_imports)] use ::buffa::alloc::string::ToString as _; let _ = __buffa_src; - super::super::EnumValueDescriptorProto { + ::core::result::Result::Ok(super::super::EnumValueDescriptorProto { name: self.name.map(|s| s.to_string()), number: self.number, options: match self.options.as_option() { Some(v) => { ::buffa::MessageField::< super::super::EnumValueOptions, - >::some(v.to_owned_from_source(__buffa_src)) + >::some(v.to_owned_from_source(__buffa_src)?) } None => ::buffa::MessageField::none(), }, - __buffa_unknown_fields: self - .__buffa_unknown_fields - .to_owned() - .unwrap_or_default() - .into(), + __buffa_unknown_fields: self.__buffa_unknown_fields.to_owned()?.into(), ..::core::default::Default::default() - } + }) } } impl<'a> ::buffa::ViewEncode<'a> for EnumValueDescriptorProtoView<'a> { @@ -6339,8 +6484,17 @@ impl EnumValueDescriptorProtoOwnedView { self.0.reborrow() } /// Convert to the owned message type. - #[must_use] - pub fn to_owned_message(&self) -> super::super::EnumValueDescriptorProto { + /// + /// # 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, + > { self.0.to_owned_message() } /// The underlying bytes buffer. @@ -6421,20 +6575,22 @@ pub struct ServiceDescriptorProtoView<'a> { pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, } impl<'a> ServiceDescriptorProtoView<'a> { - /// Decode from `buf`, enforcing a recursion depth limit for nested messages. + /// Decode from `buf` under the limits carried by `ctx` (recursion + /// depth and the shared unknown-field allowance). /// - /// Called by [`::buffa::MessageView::decode_view`] with [`::buffa::RECURSION_LIMIT`] - /// and by generated sub-message decode arms with `depth - 1`. + /// Called by [`::buffa::MessageView::decode_view`] with a fresh + /// default context and by generated sub-message decode arms with + /// `ctx.descend()?`. /// /// **Not part of the public API.** Named with a leading underscore to /// signal that it is for generated-code use only. #[doc(hidden)] - pub fn _decode_depth( + pub fn _decode_ctx( buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result { let mut view = Self::default(); - view._merge_into_view(buf, depth)?; + view._merge_into_view(buf, ctx)?; ::core::result::Result::Ok(view) } /// Merge fields from `buf` into this view (proto merge semantics). @@ -6448,9 +6604,9 @@ impl<'a> ServiceDescriptorProtoView<'a> { pub fn _merge_into_view( &mut self, buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result<(), ::buffa::DecodeError> { - let _ = depth; + let _ = ctx; #[allow(unused_variables)] let view = self; let mut cur: &'a [u8] = buf; @@ -6476,17 +6632,15 @@ impl<'a> ServiceDescriptorProtoView<'a> { actual: tag.wire_type() as u8, }); } - if depth == 0 { - return Err(::buffa::DecodeError::RecursionLimitExceeded); - } + let __sub_ctx = ctx.descend()?; let sub = ::buffa::types::borrow_bytes(&mut cur)?; match view.options.as_mut() { - Some(existing) => existing._merge_into_view(sub, depth - 1)?, + Some(existing) => existing._merge_into_view(sub, __sub_ctx)?, None => { view.options = ::buffa::MessageFieldView::set( - super::super::__buffa::view::ServiceOptionsView::_decode_depth( + super::super::__buffa::view::ServiceOptionsView::_decode_ctx( sub, - depth - 1, + __sub_ctx, )?, ); } @@ -6500,22 +6654,20 @@ impl<'a> ServiceDescriptorProtoView<'a> { actual: tag.wire_type() as u8, }); } - if depth == 0 { - return Err(::buffa::DecodeError::RecursionLimitExceeded); - } + let __sub_ctx = ctx.descend()?; let sub = ::buffa::types::borrow_bytes(&mut cur)?; view.method .push( - super::super::__buffa::view::MethodDescriptorProtoView::_decode_depth( + super::super::__buffa::view::MethodDescriptorProtoView::_decode_ctx( sub, - depth - 1, + __sub_ctx, )?, ); } _ => { - ::buffa::encoding::skip_field_depth(tag, &mut cur, depth)?; + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; let span_len = before_tag.len() - cur.len(); - view.__buffa_unknown_fields.push_raw(&before_tag[..span_len]); + view.__buffa_unknown_fields.push_record(before_tag, span_len, ctx)?; } } } @@ -6525,47 +6677,55 @@ impl<'a> ServiceDescriptorProtoView<'a> { impl<'a> ::buffa::MessageView<'a> for ServiceDescriptorProtoView<'a> { type Owned = super::super::ServiceDescriptorProto; fn decode_view(buf: &'a [u8]) -> ::core::result::Result { - Self::_decode_depth(buf, ::buffa::RECURSION_LIMIT) + let __limit = ::core::cell::Cell::new(::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT); + Self::_decode_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit), + ) } - fn decode_view_with_limit( + fn decode_view_with_ctx( buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result { - Self::_decode_depth(buf, depth) + Self::_decode_ctx(buf, ctx) } - fn to_owned_message(&self) -> super::super::ServiceDescriptorProto { + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::ServiceDescriptorProto, + ::buffa::DecodeError, + > { self.to_owned_from_source(None) } #[allow(clippy::useless_conversion, clippy::needless_update)] fn to_owned_from_source( &self, __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, - ) -> super::super::ServiceDescriptorProto { + ) -> ::core::result::Result< + super::super::ServiceDescriptorProto, + ::buffa::DecodeError, + > { #[allow(unused_imports)] use ::buffa::alloc::string::ToString as _; let _ = __buffa_src; - super::super::ServiceDescriptorProto { + ::core::result::Result::Ok(super::super::ServiceDescriptorProto { name: self.name.map(|s| s.to_string()), method: self .method .iter() .map(|v| v.to_owned_from_source(__buffa_src)) - .collect(), + .collect::<::core::result::Result<_, ::buffa::DecodeError>>()?, options: match self.options.as_option() { Some(v) => { ::buffa::MessageField::< super::super::ServiceOptions, - >::some(v.to_owned_from_source(__buffa_src)) + >::some(v.to_owned_from_source(__buffa_src)?) } None => ::buffa::MessageField::none(), }, - __buffa_unknown_fields: self - .__buffa_unknown_fields - .to_owned() - .unwrap_or_default() - .into(), + __buffa_unknown_fields: self.__buffa_unknown_fields.to_owned()?.into(), ..::core::default::Default::default() - } + }) } } impl<'a> ::buffa::ViewEncode<'a> for ServiceDescriptorProtoView<'a> { @@ -6752,8 +6912,17 @@ impl ServiceDescriptorProtoOwnedView { self.0.reborrow() } /// Convert to the owned message type. - #[must_use] - pub fn to_owned_message(&self) -> super::super::ServiceDescriptorProto { + /// + /// # 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, + > { self.0.to_owned_message() } /// The underlying bytes buffer. @@ -6849,20 +7018,22 @@ pub struct MethodDescriptorProtoView<'a> { pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, } impl<'a> MethodDescriptorProtoView<'a> { - /// Decode from `buf`, enforcing a recursion depth limit for nested messages. + /// Decode from `buf` under the limits carried by `ctx` (recursion + /// depth and the shared unknown-field allowance). /// - /// Called by [`::buffa::MessageView::decode_view`] with [`::buffa::RECURSION_LIMIT`] - /// and by generated sub-message decode arms with `depth - 1`. + /// Called by [`::buffa::MessageView::decode_view`] with a fresh + /// default context and by generated sub-message decode arms with + /// `ctx.descend()?`. /// /// **Not part of the public API.** Named with a leading underscore to /// signal that it is for generated-code use only. #[doc(hidden)] - pub fn _decode_depth( + pub fn _decode_ctx( buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result { let mut view = Self::default(); - view._merge_into_view(buf, depth)?; + view._merge_into_view(buf, ctx)?; ::core::result::Result::Ok(view) } /// Merge fields from `buf` into this view (proto merge semantics). @@ -6876,9 +7047,9 @@ impl<'a> MethodDescriptorProtoView<'a> { pub fn _merge_into_view( &mut self, buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result<(), ::buffa::DecodeError> { - let _ = depth; + let _ = ctx; #[allow(unused_variables)] let view = self; let mut cur: &'a [u8] = buf; @@ -6924,17 +7095,15 @@ impl<'a> MethodDescriptorProtoView<'a> { actual: tag.wire_type() as u8, }); } - if depth == 0 { - return Err(::buffa::DecodeError::RecursionLimitExceeded); - } + let __sub_ctx = ctx.descend()?; let sub = ::buffa::types::borrow_bytes(&mut cur)?; match view.options.as_mut() { - Some(existing) => existing._merge_into_view(sub, depth - 1)?, + Some(existing) => existing._merge_into_view(sub, __sub_ctx)?, None => { view.options = ::buffa::MessageFieldView::set( - super::super::__buffa::view::MethodOptionsView::_decode_depth( + super::super::__buffa::view::MethodOptionsView::_decode_ctx( sub, - depth - 1, + __sub_ctx, )?, ); } @@ -6961,9 +7130,9 @@ impl<'a> MethodDescriptorProtoView<'a> { view.server_streaming = Some(::buffa::types::decode_bool(&mut cur)?); } _ => { - ::buffa::encoding::skip_field_depth(tag, &mut cur, depth)?; + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; let span_len = before_tag.len() - cur.len(); - view.__buffa_unknown_fields.push_raw(&before_tag[..span_len]); + view.__buffa_unknown_fields.push_record(before_tag, span_len, ctx)?; } } } @@ -6973,26 +7142,38 @@ impl<'a> MethodDescriptorProtoView<'a> { impl<'a> ::buffa::MessageView<'a> for MethodDescriptorProtoView<'a> { type Owned = super::super::MethodDescriptorProto; fn decode_view(buf: &'a [u8]) -> ::core::result::Result { - Self::_decode_depth(buf, ::buffa::RECURSION_LIMIT) + let __limit = ::core::cell::Cell::new(::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT); + Self::_decode_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit), + ) } - fn decode_view_with_limit( + fn decode_view_with_ctx( buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result { - Self::_decode_depth(buf, depth) + Self::_decode_ctx(buf, ctx) } - fn to_owned_message(&self) -> super::super::MethodDescriptorProto { + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::MethodDescriptorProto, + ::buffa::DecodeError, + > { self.to_owned_from_source(None) } #[allow(clippy::useless_conversion, clippy::needless_update)] fn to_owned_from_source( &self, __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, - ) -> super::super::MethodDescriptorProto { + ) -> ::core::result::Result< + super::super::MethodDescriptorProto, + ::buffa::DecodeError, + > { #[allow(unused_imports)] use ::buffa::alloc::string::ToString as _; let _ = __buffa_src; - super::super::MethodDescriptorProto { + ::core::result::Result::Ok(super::super::MethodDescriptorProto { name: self.name.map(|s| s.to_string()), input_type: self.input_type.map(|s| s.to_string()), output_type: self.output_type.map(|s| s.to_string()), @@ -7000,19 +7181,15 @@ impl<'a> ::buffa::MessageView<'a> for MethodDescriptorProtoView<'a> { Some(v) => { ::buffa::MessageField::< super::super::MethodOptions, - >::some(v.to_owned_from_source(__buffa_src)) + >::some(v.to_owned_from_source(__buffa_src)?) } None => ::buffa::MessageField::none(), }, client_streaming: self.client_streaming, server_streaming: self.server_streaming, - __buffa_unknown_fields: self - .__buffa_unknown_fields - .to_owned() - .unwrap_or_default() - .into(), + __buffa_unknown_fields: self.__buffa_unknown_fields.to_owned()?.into(), ..::core::default::Default::default() - } + }) } } impl<'a> ::buffa::ViewEncode<'a> for MethodDescriptorProtoView<'a> { @@ -7229,8 +7406,17 @@ impl MethodDescriptorProtoOwnedView { self.0.reborrow() } /// Convert to the owned message type. - #[must_use] - pub fn to_owned_message(&self) -> super::super::MethodDescriptorProto { + /// + /// # 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, + > { self.0.to_owned_message() } /// The underlying bytes buffer. @@ -7486,20 +7672,22 @@ pub struct FileOptionsView<'a> { pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, } impl<'a> FileOptionsView<'a> { - /// Decode from `buf`, enforcing a recursion depth limit for nested messages. + /// Decode from `buf` under the limits carried by `ctx` (recursion + /// depth and the shared unknown-field allowance). /// - /// Called by [`::buffa::MessageView::decode_view`] with [`::buffa::RECURSION_LIMIT`] - /// and by generated sub-message decode arms with `depth - 1`. + /// Called by [`::buffa::MessageView::decode_view`] with a fresh + /// default context and by generated sub-message decode arms with + /// `ctx.descend()?`. /// /// **Not part of the public API.** Named with a leading underscore to /// signal that it is for generated-code use only. #[doc(hidden)] - pub fn _decode_depth( + pub fn _decode_ctx( buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result { let mut view = Self::default(); - view._merge_into_view(buf, depth)?; + view._merge_into_view(buf, ctx)?; ::core::result::Result::Ok(view) } /// Merge fields from `buf` into this view (proto merge semantics). @@ -7513,9 +7701,9 @@ impl<'a> FileOptionsView<'a> { pub fn _merge_into_view( &mut self, buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result<(), ::buffa::DecodeError> { - let _ = depth; + let _ = ctx; #[allow(unused_variables)] let view = self; let mut cur: &'a [u8] = buf; @@ -7596,7 +7784,8 @@ impl<'a> FileOptionsView<'a> { view.optimize_for = Some(__v); } else { let __span_len = before_tag.len() - cur.len(); - view.__buffa_unknown_fields.push_raw(&before_tag[..__span_len]); + view.__buffa_unknown_fields + .push_record(before_tag, __span_len, ctx)?; } } 11u32 => { @@ -7745,17 +7934,15 @@ impl<'a> FileOptionsView<'a> { actual: tag.wire_type() as u8, }); } - if depth == 0 { - return Err(::buffa::DecodeError::RecursionLimitExceeded); - } + let __sub_ctx = ctx.descend()?; let sub = ::buffa::types::borrow_bytes(&mut cur)?; match view.features.as_mut() { - Some(existing) => existing._merge_into_view(sub, depth - 1)?, + Some(existing) => existing._merge_into_view(sub, __sub_ctx)?, None => { view.features = ::buffa::MessageFieldView::set( - super::super::__buffa::view::FeatureSetView::_decode_depth( + super::super::__buffa::view::FeatureSetView::_decode_ctx( sub, - depth - 1, + __sub_ctx, )?, ); } @@ -7769,22 +7956,20 @@ impl<'a> FileOptionsView<'a> { actual: tag.wire_type() as u8, }); } - if depth == 0 { - return Err(::buffa::DecodeError::RecursionLimitExceeded); - } + let __sub_ctx = ctx.descend()?; let sub = ::buffa::types::borrow_bytes(&mut cur)?; view.uninterpreted_option .push( - super::super::__buffa::view::UninterpretedOptionView::_decode_depth( + super::super::__buffa::view::UninterpretedOptionView::_decode_ctx( sub, - depth - 1, + __sub_ctx, )?, ); } _ => { - ::buffa::encoding::skip_field_depth(tag, &mut cur, depth)?; + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; let span_len = before_tag.len() - cur.len(); - view.__buffa_unknown_fields.push_raw(&before_tag[..span_len]); + view.__buffa_unknown_fields.push_record(before_tag, span_len, ctx)?; } } } @@ -7794,26 +7979,32 @@ impl<'a> FileOptionsView<'a> { impl<'a> ::buffa::MessageView<'a> for FileOptionsView<'a> { type Owned = super::super::FileOptions; fn decode_view(buf: &'a [u8]) -> ::core::result::Result { - Self::_decode_depth(buf, ::buffa::RECURSION_LIMIT) + let __limit = ::core::cell::Cell::new(::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT); + Self::_decode_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit), + ) } - fn decode_view_with_limit( + fn decode_view_with_ctx( buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result { - Self::_decode_depth(buf, depth) + Self::_decode_ctx(buf, ctx) } - fn to_owned_message(&self) -> super::super::FileOptions { + fn to_owned_message( + &self, + ) -> ::core::result::Result { self.to_owned_from_source(None) } #[allow(clippy::useless_conversion, clippy::needless_update)] fn to_owned_from_source( &self, __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, - ) -> super::super::FileOptions { + ) -> ::core::result::Result { #[allow(unused_imports)] use ::buffa::alloc::string::ToString as _; let _ = __buffa_src; - super::super::FileOptions { + ::core::result::Result::Ok(super::super::FileOptions { java_package: self.java_package.map(|s| s.to_string()), java_outer_classname: self.java_outer_classname.map(|s| s.to_string()), java_multiple_files: self.java_multiple_files, @@ -7837,7 +8028,7 @@ impl<'a> ::buffa::MessageView<'a> for FileOptionsView<'a> { Some(v) => { ::buffa::MessageField::< super::super::FeatureSet, - >::some(v.to_owned_from_source(__buffa_src)) + >::some(v.to_owned_from_source(__buffa_src)?) } None => ::buffa::MessageField::none(), }, @@ -7845,14 +8036,10 @@ impl<'a> ::buffa::MessageView<'a> for FileOptionsView<'a> { .uninterpreted_option .iter() .map(|v| v.to_owned_from_source(__buffa_src)) - .collect(), - __buffa_unknown_fields: self - .__buffa_unknown_fields - .to_owned() - .unwrap_or_default() - .into(), + .collect::<::core::result::Result<_, ::buffa::DecodeError>>()?, + __buffa_unknown_fields: self.__buffa_unknown_fields.to_owned()?.into(), ..::core::default::Default::default() - } + }) } } impl<'a> ::buffa::ViewEncode<'a> for FileOptionsView<'a> { @@ -8269,8 +8456,14 @@ impl FileOptionsOwnedView { self.0.reborrow() } /// Convert to the owned message type. - #[must_use] - pub fn to_owned_message(&self) -> super::super::FileOptions { + /// + /// # 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 { self.0.to_owned_message() } /// The underlying bytes buffer. @@ -8616,20 +8809,22 @@ pub struct MessageOptionsView<'a> { pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, } impl<'a> MessageOptionsView<'a> { - /// Decode from `buf`, enforcing a recursion depth limit for nested messages. + /// Decode from `buf` under the limits carried by `ctx` (recursion + /// depth and the shared unknown-field allowance). /// - /// Called by [`::buffa::MessageView::decode_view`] with [`::buffa::RECURSION_LIMIT`] - /// and by generated sub-message decode arms with `depth - 1`. + /// Called by [`::buffa::MessageView::decode_view`] with a fresh + /// default context and by generated sub-message decode arms with + /// `ctx.descend()?`. /// /// **Not part of the public API.** Named with a leading underscore to /// signal that it is for generated-code use only. #[doc(hidden)] - pub fn _decode_depth( + pub fn _decode_ctx( buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result { let mut view = Self::default(); - view._merge_into_view(buf, depth)?; + view._merge_into_view(buf, ctx)?; ::core::result::Result::Ok(view) } /// Merge fields from `buf` into this view (proto merge semantics). @@ -8643,9 +8838,9 @@ impl<'a> MessageOptionsView<'a> { pub fn _merge_into_view( &mut self, buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result<(), ::buffa::DecodeError> { - let _ = depth; + let _ = ctx; #[allow(unused_variables)] let view = self; let mut cur: &'a [u8] = buf; @@ -8717,17 +8912,15 @@ impl<'a> MessageOptionsView<'a> { actual: tag.wire_type() as u8, }); } - if depth == 0 { - return Err(::buffa::DecodeError::RecursionLimitExceeded); - } + let __sub_ctx = ctx.descend()?; let sub = ::buffa::types::borrow_bytes(&mut cur)?; match view.features.as_mut() { - Some(existing) => existing._merge_into_view(sub, depth - 1)?, + Some(existing) => existing._merge_into_view(sub, __sub_ctx)?, None => { view.features = ::buffa::MessageFieldView::set( - super::super::__buffa::view::FeatureSetView::_decode_depth( + super::super::__buffa::view::FeatureSetView::_decode_ctx( sub, - depth - 1, + __sub_ctx, )?, ); } @@ -8741,22 +8934,20 @@ impl<'a> MessageOptionsView<'a> { actual: tag.wire_type() as u8, }); } - if depth == 0 { - return Err(::buffa::DecodeError::RecursionLimitExceeded); - } + let __sub_ctx = ctx.descend()?; let sub = ::buffa::types::borrow_bytes(&mut cur)?; view.uninterpreted_option .push( - super::super::__buffa::view::UninterpretedOptionView::_decode_depth( + super::super::__buffa::view::UninterpretedOptionView::_decode_ctx( sub, - depth - 1, + __sub_ctx, )?, ); } _ => { - ::buffa::encoding::skip_field_depth(tag, &mut cur, depth)?; + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; let span_len = before_tag.len() - cur.len(); - view.__buffa_unknown_fields.push_raw(&before_tag[..span_len]); + view.__buffa_unknown_fields.push_record(before_tag, span_len, ctx)?; } } } @@ -8766,26 +8957,32 @@ impl<'a> MessageOptionsView<'a> { impl<'a> ::buffa::MessageView<'a> for MessageOptionsView<'a> { type Owned = super::super::MessageOptions; fn decode_view(buf: &'a [u8]) -> ::core::result::Result { - Self::_decode_depth(buf, ::buffa::RECURSION_LIMIT) + let __limit = ::core::cell::Cell::new(::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT); + Self::_decode_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit), + ) } - fn decode_view_with_limit( + fn decode_view_with_ctx( buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result { - Self::_decode_depth(buf, depth) + Self::_decode_ctx(buf, ctx) } - fn to_owned_message(&self) -> super::super::MessageOptions { + fn to_owned_message( + &self, + ) -> ::core::result::Result { self.to_owned_from_source(None) } #[allow(clippy::useless_conversion, clippy::needless_update)] fn to_owned_from_source( &self, __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, - ) -> super::super::MessageOptions { + ) -> ::core::result::Result { #[allow(unused_imports)] use ::buffa::alloc::string::ToString as _; let _ = __buffa_src; - super::super::MessageOptions { + ::core::result::Result::Ok(super::super::MessageOptions { message_set_wire_format: self.message_set_wire_format, no_standard_descriptor_accessor: self.no_standard_descriptor_accessor, deprecated: self.deprecated, @@ -8796,7 +8993,7 @@ impl<'a> ::buffa::MessageView<'a> for MessageOptionsView<'a> { Some(v) => { ::buffa::MessageField::< super::super::FeatureSet, - >::some(v.to_owned_from_source(__buffa_src)) + >::some(v.to_owned_from_source(__buffa_src)?) } None => ::buffa::MessageField::none(), }, @@ -8804,14 +9001,10 @@ impl<'a> ::buffa::MessageView<'a> for MessageOptionsView<'a> { .uninterpreted_option .iter() .map(|v| v.to_owned_from_source(__buffa_src)) - .collect(), - __buffa_unknown_fields: self - .__buffa_unknown_fields - .to_owned() - .unwrap_or_default() - .into(), + .collect::<::core::result::Result<_, ::buffa::DecodeError>>()?, + __buffa_unknown_fields: self.__buffa_unknown_fields.to_owned()?.into(), ..::core::default::Default::default() - } + }) } } impl<'a> ::buffa::ViewEncode<'a> for MessageOptionsView<'a> { @@ -9039,8 +9232,14 @@ impl MessageOptionsOwnedView { self.0.reborrow() } /// Convert to the owned message type. - #[must_use] - pub fn to_owned_message(&self) -> super::super::MessageOptions { + /// + /// # 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 { self.0.to_owned_message() } /// The underlying bytes buffer. @@ -9322,20 +9521,22 @@ pub struct FieldOptionsView<'a> { pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, } impl<'a> FieldOptionsView<'a> { - /// Decode from `buf`, enforcing a recursion depth limit for nested messages. + /// Decode from `buf` under the limits carried by `ctx` (recursion + /// depth and the shared unknown-field allowance). /// - /// Called by [`::buffa::MessageView::decode_view`] with [`::buffa::RECURSION_LIMIT`] - /// and by generated sub-message decode arms with `depth - 1`. + /// Called by [`::buffa::MessageView::decode_view`] with a fresh + /// default context and by generated sub-message decode arms with + /// `ctx.descend()?`. /// /// **Not part of the public API.** Named with a leading underscore to /// signal that it is for generated-code use only. #[doc(hidden)] - pub fn _decode_depth( + pub fn _decode_ctx( buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result { let mut view = Self::default(); - view._merge_into_view(buf, depth)?; + view._merge_into_view(buf, ctx)?; ::core::result::Result::Ok(view) } /// Merge fields from `buf` into this view (proto merge semantics). @@ -9349,9 +9550,9 @@ impl<'a> FieldOptionsView<'a> { pub fn _merge_into_view( &mut self, buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result<(), ::buffa::DecodeError> { - let _ = depth; + let _ = ctx; #[allow(unused_variables)] let view = self; let mut cur: &'a [u8] = buf; @@ -9374,7 +9575,8 @@ impl<'a> FieldOptionsView<'a> { view.ctype = Some(__v); } else { let __span_len = before_tag.len() - cur.len(); - view.__buffa_unknown_fields.push_raw(&before_tag[..__span_len]); + view.__buffa_unknown_fields + .push_record(before_tag, __span_len, ctx)?; } } 2u32 => { @@ -9402,7 +9604,8 @@ impl<'a> FieldOptionsView<'a> { view.jstype = Some(__v); } else { let __span_len = before_tag.len() - cur.len(); - view.__buffa_unknown_fields.push_raw(&before_tag[..__span_len]); + view.__buffa_unknown_fields + .push_record(before_tag, __span_len, ctx)?; } } 5u32 => { @@ -9470,7 +9673,8 @@ impl<'a> FieldOptionsView<'a> { view.retention = Some(__v); } else { let __span_len = before_tag.len() - cur.len(); - view.__buffa_unknown_fields.push_raw(&before_tag[..__span_len]); + view.__buffa_unknown_fields + .push_record(before_tag, __span_len, ctx)?; } } 21u32 => { @@ -9481,17 +9685,15 @@ impl<'a> FieldOptionsView<'a> { actual: tag.wire_type() as u8, }); } - if depth == 0 { - return Err(::buffa::DecodeError::RecursionLimitExceeded); - } + let __sub_ctx = ctx.descend()?; let sub = ::buffa::types::borrow_bytes(&mut cur)?; match view.features.as_mut() { - Some(existing) => existing._merge_into_view(sub, depth - 1)?, + Some(existing) => existing._merge_into_view(sub, __sub_ctx)?, None => { view.features = ::buffa::MessageFieldView::set( - super::super::__buffa::view::FeatureSetView::_decode_depth( + super::super::__buffa::view::FeatureSetView::_decode_ctx( sub, - depth - 1, + __sub_ctx, )?, ); } @@ -9505,17 +9707,15 @@ impl<'a> FieldOptionsView<'a> { actual: tag.wire_type() as u8, }); } - if depth == 0 { - return Err(::buffa::DecodeError::RecursionLimitExceeded); - } + let __sub_ctx = ctx.descend()?; let sub = ::buffa::types::borrow_bytes(&mut cur)?; match view.feature_support.as_mut() { - Some(existing) => existing._merge_into_view(sub, depth - 1)?, + Some(existing) => existing._merge_into_view(sub, __sub_ctx)?, None => { view.feature_support = ::buffa::MessageFieldView::set( - super::super::__buffa::view::field_options::FeatureSupportView::_decode_depth( + super::super::__buffa::view::field_options::FeatureSupportView::_decode_ctx( sub, - depth - 1, + __sub_ctx, )?, ); } @@ -9543,7 +9743,7 @@ impl<'a> FieldOptionsView<'a> { } else { let __span_len = before_tag.len() - cur.len(); view.__buffa_unknown_fields - .push_raw(&before_tag[..__span_len]); + .push_record(before_tag, __span_len, ctx)?; } } else { return Err(::buffa::DecodeError::WireTypeMismatch { @@ -9561,15 +9761,13 @@ impl<'a> FieldOptionsView<'a> { actual: tag.wire_type() as u8, }); } - if depth == 0 { - return Err(::buffa::DecodeError::RecursionLimitExceeded); - } + let __sub_ctx = ctx.descend()?; let sub = ::buffa::types::borrow_bytes(&mut cur)?; view.edition_defaults .push( - super::super::__buffa::view::field_options::EditionDefaultView::_decode_depth( + super::super::__buffa::view::field_options::EditionDefaultView::_decode_ctx( sub, - depth - 1, + __sub_ctx, )?, ); } @@ -9581,22 +9779,20 @@ impl<'a> FieldOptionsView<'a> { actual: tag.wire_type() as u8, }); } - if depth == 0 { - return Err(::buffa::DecodeError::RecursionLimitExceeded); - } + let __sub_ctx = ctx.descend()?; let sub = ::buffa::types::borrow_bytes(&mut cur)?; view.uninterpreted_option .push( - super::super::__buffa::view::UninterpretedOptionView::_decode_depth( + super::super::__buffa::view::UninterpretedOptionView::_decode_ctx( sub, - depth - 1, + __sub_ctx, )?, ); } _ => { - ::buffa::encoding::skip_field_depth(tag, &mut cur, depth)?; + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; let span_len = before_tag.len() - cur.len(); - view.__buffa_unknown_fields.push_raw(&before_tag[..span_len]); + view.__buffa_unknown_fields.push_record(before_tag, span_len, ctx)?; } } } @@ -9606,26 +9802,32 @@ impl<'a> FieldOptionsView<'a> { impl<'a> ::buffa::MessageView<'a> for FieldOptionsView<'a> { type Owned = super::super::FieldOptions; fn decode_view(buf: &'a [u8]) -> ::core::result::Result { - Self::_decode_depth(buf, ::buffa::RECURSION_LIMIT) + let __limit = ::core::cell::Cell::new(::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT); + Self::_decode_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit), + ) } - fn decode_view_with_limit( + fn decode_view_with_ctx( buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result { - Self::_decode_depth(buf, depth) + Self::_decode_ctx(buf, ctx) } - fn to_owned_message(&self) -> super::super::FieldOptions { + fn to_owned_message( + &self, + ) -> ::core::result::Result { self.to_owned_from_source(None) } #[allow(clippy::useless_conversion, clippy::needless_update)] fn to_owned_from_source( &self, __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, - ) -> super::super::FieldOptions { + ) -> ::core::result::Result { #[allow(unused_imports)] use ::buffa::alloc::string::ToString as _; let _ = __buffa_src; - super::super::FieldOptions { + ::core::result::Result::Ok(super::super::FieldOptions { ctype: self.ctype, packed: self.packed, jstype: self.jstype, @@ -9640,12 +9842,12 @@ impl<'a> ::buffa::MessageView<'a> for FieldOptionsView<'a> { .edition_defaults .iter() .map(|v| v.to_owned_from_source(__buffa_src)) - .collect(), + .collect::<::core::result::Result<_, ::buffa::DecodeError>>()?, features: match self.features.as_option() { Some(v) => { ::buffa::MessageField::< super::super::FeatureSet, - >::some(v.to_owned_from_source(__buffa_src)) + >::some(v.to_owned_from_source(__buffa_src)?) } None => ::buffa::MessageField::none(), }, @@ -9653,7 +9855,7 @@ impl<'a> ::buffa::MessageView<'a> for FieldOptionsView<'a> { Some(v) => { ::buffa::MessageField::< super::super::field_options::FeatureSupport, - >::some(v.to_owned_from_source(__buffa_src)) + >::some(v.to_owned_from_source(__buffa_src)?) } None => ::buffa::MessageField::none(), }, @@ -9661,14 +9863,10 @@ impl<'a> ::buffa::MessageView<'a> for FieldOptionsView<'a> { .uninterpreted_option .iter() .map(|v| v.to_owned_from_source(__buffa_src)) - .collect(), - __buffa_unknown_fields: self - .__buffa_unknown_fields - .to_owned() - .unwrap_or_default() - .into(), + .collect::<::core::result::Result<_, ::buffa::DecodeError>>()?, + __buffa_unknown_fields: self.__buffa_unknown_fields.to_owned()?.into(), ..::core::default::Default::default() - } + }) } } impl<'a> ::buffa::ViewEncode<'a> for FieldOptionsView<'a> { @@ -10025,8 +10223,14 @@ impl FieldOptionsOwnedView { self.0.reborrow() } /// Convert to the owned message type. - #[must_use] - pub fn to_owned_message(&self) -> super::super::FieldOptions { + /// + /// # 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 { self.0.to_owned_message() } /// The underlying bytes buffer. @@ -10248,20 +10452,22 @@ pub mod field_options { pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, } impl<'a> EditionDefaultView<'a> { - /// Decode from `buf`, enforcing a recursion depth limit for nested messages. + /// Decode from `buf` under the limits carried by `ctx` (recursion + /// depth and the shared unknown-field allowance). /// - /// Called by [`::buffa::MessageView::decode_view`] with [`::buffa::RECURSION_LIMIT`] - /// and by generated sub-message decode arms with `depth - 1`. + /// Called by [`::buffa::MessageView::decode_view`] with a fresh + /// default context and by generated sub-message decode arms with + /// `ctx.descend()?`. /// /// **Not part of the public API.** Named with a leading underscore to /// signal that it is for generated-code use only. #[doc(hidden)] - pub fn _decode_depth( + pub fn _decode_ctx( buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result { let mut view = Self::default(); - view._merge_into_view(buf, depth)?; + view._merge_into_view(buf, ctx)?; ::core::result::Result::Ok(view) } /// Merge fields from `buf` into this view (proto merge semantics). @@ -10275,9 +10481,9 @@ pub mod field_options { pub fn _merge_into_view( &mut self, buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result<(), ::buffa::DecodeError> { - let _ = depth; + let _ = ctx; #[allow(unused_variables)] let view = self; let mut cur: &'a [u8] = buf; @@ -10301,7 +10507,7 @@ pub mod field_options { } else { let __span_len = before_tag.len() - cur.len(); view.__buffa_unknown_fields - .push_raw(&before_tag[..__span_len]); + .push_record(before_tag, __span_len, ctx)?; } } 2u32 => { @@ -10317,9 +10523,10 @@ pub mod field_options { view.value = Some(::buffa::types::borrow_str(&mut cur)?); } _ => { - ::buffa::encoding::skip_field_depth(tag, &mut cur, depth)?; + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; let span_len = before_tag.len() - cur.len(); - view.__buffa_unknown_fields.push_raw(&before_tag[..span_len]); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; } } } @@ -10331,37 +10538,43 @@ pub mod field_options { fn decode_view( buf: &'a [u8], ) -> ::core::result::Result { - Self::_decode_depth(buf, ::buffa::RECURSION_LIMIT) + let __limit = ::core::cell::Cell::new(::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT); + Self::_decode_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit), + ) } - fn decode_view_with_limit( + fn decode_view_with_ctx( buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result { - Self::_decode_depth(buf, depth) + Self::_decode_ctx(buf, ctx) } fn to_owned_message( &self, - ) -> super::super::super::field_options::EditionDefault { + ) -> ::core::result::Result< + super::super::super::field_options::EditionDefault, + ::buffa::DecodeError, + > { self.to_owned_from_source(None) } #[allow(clippy::useless_conversion, clippy::needless_update)] fn to_owned_from_source( &self, __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, - ) -> super::super::super::field_options::EditionDefault { + ) -> ::core::result::Result< + super::super::super::field_options::EditionDefault, + ::buffa::DecodeError, + > { #[allow(unused_imports)] use ::buffa::alloc::string::ToString as _; let _ = __buffa_src; - super::super::super::field_options::EditionDefault { + ::core::result::Result::Ok(super::super::super::field_options::EditionDefault { edition: self.edition, value: self.value.map(|s| s.to_string()), - __buffa_unknown_fields: self - .__buffa_unknown_fields - .to_owned() - .unwrap_or_default() - .into(), + __buffa_unknown_fields: self.__buffa_unknown_fields.to_owned()?.into(), ..::core::default::Default::default() - } + }) } } impl<'a> ::buffa::ViewEncode<'a> for EditionDefaultView<'a> { @@ -10524,10 +10737,17 @@ pub mod field_options { self.0.reborrow() } /// Convert to the owned message type. - #[must_use] + /// + /// # 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, - ) -> super::super::super::field_options::EditionDefault { + ) -> ::core::result::Result< + super::super::super::field_options::EditionDefault, + ::buffa::DecodeError, + > { self.0.to_owned_message() } /// The underlying bytes buffer. @@ -10612,20 +10832,22 @@ pub mod field_options { pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, } impl<'a> FeatureSupportView<'a> { - /// Decode from `buf`, enforcing a recursion depth limit for nested messages. + /// Decode from `buf` under the limits carried by `ctx` (recursion + /// depth and the shared unknown-field allowance). /// - /// Called by [`::buffa::MessageView::decode_view`] with [`::buffa::RECURSION_LIMIT`] - /// and by generated sub-message decode arms with `depth - 1`. + /// Called by [`::buffa::MessageView::decode_view`] with a fresh + /// default context and by generated sub-message decode arms with + /// `ctx.descend()?`. /// /// **Not part of the public API.** Named with a leading underscore to /// signal that it is for generated-code use only. #[doc(hidden)] - pub fn _decode_depth( + pub fn _decode_ctx( buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result { let mut view = Self::default(); - view._merge_into_view(buf, depth)?; + view._merge_into_view(buf, ctx)?; ::core::result::Result::Ok(view) } /// Merge fields from `buf` into this view (proto merge semantics). @@ -10639,9 +10861,9 @@ pub mod field_options { pub fn _merge_into_view( &mut self, buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result<(), ::buffa::DecodeError> { - let _ = depth; + let _ = ctx; #[allow(unused_variables)] let view = self; let mut cur: &'a [u8] = buf; @@ -10665,7 +10887,7 @@ pub mod field_options { } else { let __span_len = before_tag.len() - cur.len(); view.__buffa_unknown_fields - .push_raw(&before_tag[..__span_len]); + .push_record(before_tag, __span_len, ctx)?; } } 2u32 => { @@ -10684,7 +10906,7 @@ pub mod field_options { } else { let __span_len = before_tag.len() - cur.len(); view.__buffa_unknown_fields - .push_raw(&before_tag[..__span_len]); + .push_record(before_tag, __span_len, ctx)?; } } 3u32 => { @@ -10717,13 +10939,14 @@ pub mod field_options { } else { let __span_len = before_tag.len() - cur.len(); view.__buffa_unknown_fields - .push_raw(&before_tag[..__span_len]); + .push_record(before_tag, __span_len, ctx)?; } } _ => { - ::buffa::encoding::skip_field_depth(tag, &mut cur, depth)?; + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; let span_len = before_tag.len() - cur.len(); - view.__buffa_unknown_fields.push_raw(&before_tag[..span_len]); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; } } } @@ -10735,39 +10958,45 @@ pub mod field_options { fn decode_view( buf: &'a [u8], ) -> ::core::result::Result { - Self::_decode_depth(buf, ::buffa::RECURSION_LIMIT) + let __limit = ::core::cell::Cell::new(::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT); + Self::_decode_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit), + ) } - fn decode_view_with_limit( + fn decode_view_with_ctx( buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result { - Self::_decode_depth(buf, depth) + Self::_decode_ctx(buf, ctx) } fn to_owned_message( &self, - ) -> super::super::super::field_options::FeatureSupport { + ) -> ::core::result::Result< + super::super::super::field_options::FeatureSupport, + ::buffa::DecodeError, + > { self.to_owned_from_source(None) } #[allow(clippy::useless_conversion, clippy::needless_update)] fn to_owned_from_source( &self, __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, - ) -> super::super::super::field_options::FeatureSupport { + ) -> ::core::result::Result< + super::super::super::field_options::FeatureSupport, + ::buffa::DecodeError, + > { #[allow(unused_imports)] use ::buffa::alloc::string::ToString as _; let _ = __buffa_src; - super::super::super::field_options::FeatureSupport { + ::core::result::Result::Ok(super::super::super::field_options::FeatureSupport { edition_introduced: self.edition_introduced, edition_deprecated: self.edition_deprecated, deprecation_warning: self.deprecation_warning.map(|s| s.to_string()), edition_removed: self.edition_removed, - __buffa_unknown_fields: self - .__buffa_unknown_fields - .to_owned() - .unwrap_or_default() - .into(), + __buffa_unknown_fields: self.__buffa_unknown_fields.to_owned()?.into(), ..::core::default::Default::default() - } + }) } } impl<'a> ::buffa::ViewEncode<'a> for FeatureSupportView<'a> { @@ -10970,10 +11199,17 @@ pub mod field_options { self.0.reborrow() } /// Convert to the owned message type. - #[must_use] + /// + /// # 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, - ) -> super::super::super::field_options::FeatureSupport { + ) -> ::core::result::Result< + super::super::super::field_options::FeatureSupport, + ::buffa::DecodeError, + > { self.0.to_owned_message() } /// The underlying bytes buffer. @@ -11080,20 +11316,22 @@ pub struct OneofOptionsView<'a> { pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, } impl<'a> OneofOptionsView<'a> { - /// Decode from `buf`, enforcing a recursion depth limit for nested messages. + /// Decode from `buf` under the limits carried by `ctx` (recursion + /// depth and the shared unknown-field allowance). /// - /// Called by [`::buffa::MessageView::decode_view`] with [`::buffa::RECURSION_LIMIT`] - /// and by generated sub-message decode arms with `depth - 1`. + /// Called by [`::buffa::MessageView::decode_view`] with a fresh + /// default context and by generated sub-message decode arms with + /// `ctx.descend()?`. /// /// **Not part of the public API.** Named with a leading underscore to /// signal that it is for generated-code use only. #[doc(hidden)] - pub fn _decode_depth( + pub fn _decode_ctx( buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result { let mut view = Self::default(); - view._merge_into_view(buf, depth)?; + view._merge_into_view(buf, ctx)?; ::core::result::Result::Ok(view) } /// Merge fields from `buf` into this view (proto merge semantics). @@ -11107,9 +11345,9 @@ impl<'a> OneofOptionsView<'a> { pub fn _merge_into_view( &mut self, buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result<(), ::buffa::DecodeError> { - let _ = depth; + let _ = ctx; #[allow(unused_variables)] let view = self; let mut cur: &'a [u8] = buf; @@ -11125,17 +11363,15 @@ impl<'a> OneofOptionsView<'a> { actual: tag.wire_type() as u8, }); } - if depth == 0 { - return Err(::buffa::DecodeError::RecursionLimitExceeded); - } + let __sub_ctx = ctx.descend()?; let sub = ::buffa::types::borrow_bytes(&mut cur)?; match view.features.as_mut() { - Some(existing) => existing._merge_into_view(sub, depth - 1)?, + Some(existing) => existing._merge_into_view(sub, __sub_ctx)?, None => { view.features = ::buffa::MessageFieldView::set( - super::super::__buffa::view::FeatureSetView::_decode_depth( + super::super::__buffa::view::FeatureSetView::_decode_ctx( sub, - depth - 1, + __sub_ctx, )?, ); } @@ -11149,22 +11385,20 @@ impl<'a> OneofOptionsView<'a> { actual: tag.wire_type() as u8, }); } - if depth == 0 { - return Err(::buffa::DecodeError::RecursionLimitExceeded); - } + let __sub_ctx = ctx.descend()?; let sub = ::buffa::types::borrow_bytes(&mut cur)?; view.uninterpreted_option .push( - super::super::__buffa::view::UninterpretedOptionView::_decode_depth( + super::super::__buffa::view::UninterpretedOptionView::_decode_ctx( sub, - depth - 1, + __sub_ctx, )?, ); } _ => { - ::buffa::encoding::skip_field_depth(tag, &mut cur, depth)?; + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; let span_len = before_tag.len() - cur.len(); - view.__buffa_unknown_fields.push_raw(&before_tag[..span_len]); + view.__buffa_unknown_fields.push_record(before_tag, span_len, ctx)?; } } } @@ -11174,31 +11408,37 @@ impl<'a> OneofOptionsView<'a> { impl<'a> ::buffa::MessageView<'a> for OneofOptionsView<'a> { type Owned = super::super::OneofOptions; fn decode_view(buf: &'a [u8]) -> ::core::result::Result { - Self::_decode_depth(buf, ::buffa::RECURSION_LIMIT) + let __limit = ::core::cell::Cell::new(::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT); + Self::_decode_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit), + ) } - fn decode_view_with_limit( + fn decode_view_with_ctx( buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result { - Self::_decode_depth(buf, depth) + Self::_decode_ctx(buf, ctx) } - fn to_owned_message(&self) -> super::super::OneofOptions { + fn to_owned_message( + &self, + ) -> ::core::result::Result { self.to_owned_from_source(None) } #[allow(clippy::useless_conversion, clippy::needless_update)] fn to_owned_from_source( &self, __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, - ) -> super::super::OneofOptions { + ) -> ::core::result::Result { #[allow(unused_imports)] use ::buffa::alloc::string::ToString as _; let _ = __buffa_src; - super::super::OneofOptions { + ::core::result::Result::Ok(super::super::OneofOptions { features: match self.features.as_option() { Some(v) => { ::buffa::MessageField::< super::super::FeatureSet, - >::some(v.to_owned_from_source(__buffa_src)) + >::some(v.to_owned_from_source(__buffa_src)?) } None => ::buffa::MessageField::none(), }, @@ -11206,14 +11446,10 @@ impl<'a> ::buffa::MessageView<'a> for OneofOptionsView<'a> { .uninterpreted_option .iter() .map(|v| v.to_owned_from_source(__buffa_src)) - .collect(), - __buffa_unknown_fields: self - .__buffa_unknown_fields - .to_owned() - .unwrap_or_default() - .into(), + .collect::<::core::result::Result<_, ::buffa::DecodeError>>()?, + __buffa_unknown_fields: self.__buffa_unknown_fields.to_owned()?.into(), ..::core::default::Default::default() - } + }) } } impl<'a> ::buffa::ViewEncode<'a> for OneofOptionsView<'a> { @@ -11382,8 +11618,14 @@ impl OneofOptionsOwnedView { self.0.reborrow() } /// Convert to the owned message type. - #[must_use] - pub fn to_owned_message(&self) -> super::super::OneofOptions { + /// + /// # 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 { self.0.to_owned_message() } /// The underlying bytes buffer. @@ -11494,20 +11736,22 @@ pub struct EnumOptionsView<'a> { pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, } impl<'a> EnumOptionsView<'a> { - /// Decode from `buf`, enforcing a recursion depth limit for nested messages. + /// Decode from `buf` under the limits carried by `ctx` (recursion + /// depth and the shared unknown-field allowance). /// - /// Called by [`::buffa::MessageView::decode_view`] with [`::buffa::RECURSION_LIMIT`] - /// and by generated sub-message decode arms with `depth - 1`. + /// Called by [`::buffa::MessageView::decode_view`] with a fresh + /// default context and by generated sub-message decode arms with + /// `ctx.descend()?`. /// /// **Not part of the public API.** Named with a leading underscore to /// signal that it is for generated-code use only. #[doc(hidden)] - pub fn _decode_depth( + pub fn _decode_ctx( buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result { let mut view = Self::default(); - view._merge_into_view(buf, depth)?; + view._merge_into_view(buf, ctx)?; ::core::result::Result::Ok(view) } /// Merge fields from `buf` into this view (proto merge semantics). @@ -11521,9 +11765,9 @@ impl<'a> EnumOptionsView<'a> { pub fn _merge_into_view( &mut self, buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result<(), ::buffa::DecodeError> { - let _ = depth; + let _ = ctx; #[allow(unused_variables)] let view = self; let mut cur: &'a [u8] = buf; @@ -11571,17 +11815,15 @@ impl<'a> EnumOptionsView<'a> { actual: tag.wire_type() as u8, }); } - if depth == 0 { - return Err(::buffa::DecodeError::RecursionLimitExceeded); - } + let __sub_ctx = ctx.descend()?; let sub = ::buffa::types::borrow_bytes(&mut cur)?; match view.features.as_mut() { - Some(existing) => existing._merge_into_view(sub, depth - 1)?, + Some(existing) => existing._merge_into_view(sub, __sub_ctx)?, None => { view.features = ::buffa::MessageFieldView::set( - super::super::__buffa::view::FeatureSetView::_decode_depth( + super::super::__buffa::view::FeatureSetView::_decode_ctx( sub, - depth - 1, + __sub_ctx, )?, ); } @@ -11595,22 +11837,20 @@ impl<'a> EnumOptionsView<'a> { actual: tag.wire_type() as u8, }); } - if depth == 0 { - return Err(::buffa::DecodeError::RecursionLimitExceeded); - } + let __sub_ctx = ctx.descend()?; let sub = ::buffa::types::borrow_bytes(&mut cur)?; view.uninterpreted_option .push( - super::super::__buffa::view::UninterpretedOptionView::_decode_depth( + super::super::__buffa::view::UninterpretedOptionView::_decode_ctx( sub, - depth - 1, + __sub_ctx, )?, ); } _ => { - ::buffa::encoding::skip_field_depth(tag, &mut cur, depth)?; + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; let span_len = before_tag.len() - cur.len(); - view.__buffa_unknown_fields.push_raw(&before_tag[..span_len]); + view.__buffa_unknown_fields.push_record(before_tag, span_len, ctx)?; } } } @@ -11620,26 +11860,32 @@ impl<'a> EnumOptionsView<'a> { impl<'a> ::buffa::MessageView<'a> for EnumOptionsView<'a> { type Owned = super::super::EnumOptions; fn decode_view(buf: &'a [u8]) -> ::core::result::Result { - Self::_decode_depth(buf, ::buffa::RECURSION_LIMIT) + let __limit = ::core::cell::Cell::new(::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT); + Self::_decode_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit), + ) } - fn decode_view_with_limit( + fn decode_view_with_ctx( buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result { - Self::_decode_depth(buf, depth) + Self::_decode_ctx(buf, ctx) } - fn to_owned_message(&self) -> super::super::EnumOptions { + fn to_owned_message( + &self, + ) -> ::core::result::Result { self.to_owned_from_source(None) } #[allow(clippy::useless_conversion, clippy::needless_update)] fn to_owned_from_source( &self, __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, - ) -> super::super::EnumOptions { + ) -> ::core::result::Result { #[allow(unused_imports)] use ::buffa::alloc::string::ToString as _; let _ = __buffa_src; - super::super::EnumOptions { + ::core::result::Result::Ok(super::super::EnumOptions { allow_alias: self.allow_alias, deprecated: self.deprecated, deprecated_legacy_json_field_conflicts: self @@ -11648,7 +11894,7 @@ impl<'a> ::buffa::MessageView<'a> for EnumOptionsView<'a> { Some(v) => { ::buffa::MessageField::< super::super::FeatureSet, - >::some(v.to_owned_from_source(__buffa_src)) + >::some(v.to_owned_from_source(__buffa_src)?) } None => ::buffa::MessageField::none(), }, @@ -11656,14 +11902,10 @@ impl<'a> ::buffa::MessageView<'a> for EnumOptionsView<'a> { .uninterpreted_option .iter() .map(|v| v.to_owned_from_source(__buffa_src)) - .collect(), - __buffa_unknown_fields: self - .__buffa_unknown_fields - .to_owned() - .unwrap_or_default() - .into(), + .collect::<::core::result::Result<_, ::buffa::DecodeError>>()?, + __buffa_unknown_fields: self.__buffa_unknown_fields.to_owned()?.into(), ..::core::default::Default::default() - } + }) } } impl<'a> ::buffa::ViewEncode<'a> for EnumOptionsView<'a> { @@ -11867,8 +12109,14 @@ impl EnumOptionsOwnedView { self.0.reborrow() } /// Convert to the owned message type. - #[must_use] - pub fn to_owned_message(&self) -> super::super::EnumOptions { + /// + /// # 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 { self.0.to_owned_message() } /// The underlying bytes buffer. @@ -12009,20 +12257,22 @@ pub struct EnumValueOptionsView<'a> { pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, } impl<'a> EnumValueOptionsView<'a> { - /// Decode from `buf`, enforcing a recursion depth limit for nested messages. + /// Decode from `buf` under the limits carried by `ctx` (recursion + /// depth and the shared unknown-field allowance). /// - /// Called by [`::buffa::MessageView::decode_view`] with [`::buffa::RECURSION_LIMIT`] - /// and by generated sub-message decode arms with `depth - 1`. + /// Called by [`::buffa::MessageView::decode_view`] with a fresh + /// default context and by generated sub-message decode arms with + /// `ctx.descend()?`. /// /// **Not part of the public API.** Named with a leading underscore to /// signal that it is for generated-code use only. #[doc(hidden)] - pub fn _decode_depth( + pub fn _decode_ctx( buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result { let mut view = Self::default(); - view._merge_into_view(buf, depth)?; + view._merge_into_view(buf, ctx)?; ::core::result::Result::Ok(view) } /// Merge fields from `buf` into this view (proto merge semantics). @@ -12036,9 +12286,9 @@ impl<'a> EnumValueOptionsView<'a> { pub fn _merge_into_view( &mut self, buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result<(), ::buffa::DecodeError> { - let _ = depth; + let _ = ctx; #[allow(unused_variables)] let view = self; let mut cur: &'a [u8] = buf; @@ -12064,17 +12314,15 @@ impl<'a> EnumValueOptionsView<'a> { actual: tag.wire_type() as u8, }); } - if depth == 0 { - return Err(::buffa::DecodeError::RecursionLimitExceeded); - } + let __sub_ctx = ctx.descend()?; let sub = ::buffa::types::borrow_bytes(&mut cur)?; match view.features.as_mut() { - Some(existing) => existing._merge_into_view(sub, depth - 1)?, + Some(existing) => existing._merge_into_view(sub, __sub_ctx)?, None => { view.features = ::buffa::MessageFieldView::set( - super::super::__buffa::view::FeatureSetView::_decode_depth( + super::super::__buffa::view::FeatureSetView::_decode_ctx( sub, - depth - 1, + __sub_ctx, )?, ); } @@ -12098,17 +12346,15 @@ impl<'a> EnumValueOptionsView<'a> { actual: tag.wire_type() as u8, }); } - if depth == 0 { - return Err(::buffa::DecodeError::RecursionLimitExceeded); - } + let __sub_ctx = ctx.descend()?; let sub = ::buffa::types::borrow_bytes(&mut cur)?; match view.feature_support.as_mut() { - Some(existing) => existing._merge_into_view(sub, depth - 1)?, + Some(existing) => existing._merge_into_view(sub, __sub_ctx)?, None => { view.feature_support = ::buffa::MessageFieldView::set( - super::super::__buffa::view::field_options::FeatureSupportView::_decode_depth( + super::super::__buffa::view::field_options::FeatureSupportView::_decode_ctx( sub, - depth - 1, + __sub_ctx, )?, ); } @@ -12122,22 +12368,20 @@ impl<'a> EnumValueOptionsView<'a> { actual: tag.wire_type() as u8, }); } - if depth == 0 { - return Err(::buffa::DecodeError::RecursionLimitExceeded); - } + let __sub_ctx = ctx.descend()?; let sub = ::buffa::types::borrow_bytes(&mut cur)?; view.uninterpreted_option .push( - super::super::__buffa::view::UninterpretedOptionView::_decode_depth( + super::super::__buffa::view::UninterpretedOptionView::_decode_ctx( sub, - depth - 1, + __sub_ctx, )?, ); } _ => { - ::buffa::encoding::skip_field_depth(tag, &mut cur, depth)?; + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; let span_len = before_tag.len() - cur.len(); - view.__buffa_unknown_fields.push_raw(&before_tag[..span_len]); + view.__buffa_unknown_fields.push_record(before_tag, span_len, ctx)?; } } } @@ -12147,32 +12391,38 @@ impl<'a> EnumValueOptionsView<'a> { impl<'a> ::buffa::MessageView<'a> for EnumValueOptionsView<'a> { type Owned = super::super::EnumValueOptions; fn decode_view(buf: &'a [u8]) -> ::core::result::Result { - Self::_decode_depth(buf, ::buffa::RECURSION_LIMIT) + let __limit = ::core::cell::Cell::new(::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT); + Self::_decode_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit), + ) } - fn decode_view_with_limit( + fn decode_view_with_ctx( buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result { - Self::_decode_depth(buf, depth) + Self::_decode_ctx(buf, ctx) } - fn to_owned_message(&self) -> super::super::EnumValueOptions { + fn to_owned_message( + &self, + ) -> ::core::result::Result { self.to_owned_from_source(None) } #[allow(clippy::useless_conversion, clippy::needless_update)] fn to_owned_from_source( &self, __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, - ) -> super::super::EnumValueOptions { + ) -> ::core::result::Result { #[allow(unused_imports)] use ::buffa::alloc::string::ToString as _; let _ = __buffa_src; - super::super::EnumValueOptions { + ::core::result::Result::Ok(super::super::EnumValueOptions { deprecated: self.deprecated, features: match self.features.as_option() { Some(v) => { ::buffa::MessageField::< super::super::FeatureSet, - >::some(v.to_owned_from_source(__buffa_src)) + >::some(v.to_owned_from_source(__buffa_src)?) } None => ::buffa::MessageField::none(), }, @@ -12181,7 +12431,7 @@ impl<'a> ::buffa::MessageView<'a> for EnumValueOptionsView<'a> { Some(v) => { ::buffa::MessageField::< super::super::field_options::FeatureSupport, - >::some(v.to_owned_from_source(__buffa_src)) + >::some(v.to_owned_from_source(__buffa_src)?) } None => ::buffa::MessageField::none(), }, @@ -12189,14 +12439,10 @@ impl<'a> ::buffa::MessageView<'a> for EnumValueOptionsView<'a> { .uninterpreted_option .iter() .map(|v| v.to_owned_from_source(__buffa_src)) - .collect(), - __buffa_unknown_fields: self - .__buffa_unknown_fields - .to_owned() - .unwrap_or_default() - .into(), + .collect::<::core::result::Result<_, ::buffa::DecodeError>>()?, + __buffa_unknown_fields: self.__buffa_unknown_fields.to_owned()?.into(), ..::core::default::Default::default() - } + }) } } impl<'a> ::buffa::ViewEncode<'a> for EnumValueOptionsView<'a> { @@ -12411,8 +12657,14 @@ impl EnumValueOptionsOwnedView { self.0.reborrow() } /// Convert to the owned message type. - #[must_use] - pub fn to_owned_message(&self) -> super::super::EnumValueOptions { + /// + /// # 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 { self.0.to_owned_message() } /// The underlying bytes buffer. @@ -12544,20 +12796,22 @@ pub struct ServiceOptionsView<'a> { pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, } impl<'a> ServiceOptionsView<'a> { - /// Decode from `buf`, enforcing a recursion depth limit for nested messages. + /// Decode from `buf` under the limits carried by `ctx` (recursion + /// depth and the shared unknown-field allowance). /// - /// Called by [`::buffa::MessageView::decode_view`] with [`::buffa::RECURSION_LIMIT`] - /// and by generated sub-message decode arms with `depth - 1`. + /// Called by [`::buffa::MessageView::decode_view`] with a fresh + /// default context and by generated sub-message decode arms with + /// `ctx.descend()?`. /// /// **Not part of the public API.** Named with a leading underscore to /// signal that it is for generated-code use only. #[doc(hidden)] - pub fn _decode_depth( + pub fn _decode_ctx( buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result { let mut view = Self::default(); - view._merge_into_view(buf, depth)?; + view._merge_into_view(buf, ctx)?; ::core::result::Result::Ok(view) } /// Merge fields from `buf` into this view (proto merge semantics). @@ -12571,9 +12825,9 @@ impl<'a> ServiceOptionsView<'a> { pub fn _merge_into_view( &mut self, buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result<(), ::buffa::DecodeError> { - let _ = depth; + let _ = ctx; #[allow(unused_variables)] let view = self; let mut cur: &'a [u8] = buf; @@ -12589,17 +12843,15 @@ impl<'a> ServiceOptionsView<'a> { actual: tag.wire_type() as u8, }); } - if depth == 0 { - return Err(::buffa::DecodeError::RecursionLimitExceeded); - } + let __sub_ctx = ctx.descend()?; let sub = ::buffa::types::borrow_bytes(&mut cur)?; match view.features.as_mut() { - Some(existing) => existing._merge_into_view(sub, depth - 1)?, + Some(existing) => existing._merge_into_view(sub, __sub_ctx)?, None => { view.features = ::buffa::MessageFieldView::set( - super::super::__buffa::view::FeatureSetView::_decode_depth( + super::super::__buffa::view::FeatureSetView::_decode_ctx( sub, - depth - 1, + __sub_ctx, )?, ); } @@ -12623,22 +12875,20 @@ impl<'a> ServiceOptionsView<'a> { actual: tag.wire_type() as u8, }); } - if depth == 0 { - return Err(::buffa::DecodeError::RecursionLimitExceeded); - } + let __sub_ctx = ctx.descend()?; let sub = ::buffa::types::borrow_bytes(&mut cur)?; view.uninterpreted_option .push( - super::super::__buffa::view::UninterpretedOptionView::_decode_depth( + super::super::__buffa::view::UninterpretedOptionView::_decode_ctx( sub, - depth - 1, + __sub_ctx, )?, ); } _ => { - ::buffa::encoding::skip_field_depth(tag, &mut cur, depth)?; + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; let span_len = before_tag.len() - cur.len(); - view.__buffa_unknown_fields.push_raw(&before_tag[..span_len]); + view.__buffa_unknown_fields.push_record(before_tag, span_len, ctx)?; } } } @@ -12648,31 +12898,37 @@ impl<'a> ServiceOptionsView<'a> { impl<'a> ::buffa::MessageView<'a> for ServiceOptionsView<'a> { type Owned = super::super::ServiceOptions; fn decode_view(buf: &'a [u8]) -> ::core::result::Result { - Self::_decode_depth(buf, ::buffa::RECURSION_LIMIT) + let __limit = ::core::cell::Cell::new(::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT); + Self::_decode_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit), + ) } - fn decode_view_with_limit( + fn decode_view_with_ctx( buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result { - Self::_decode_depth(buf, depth) + Self::_decode_ctx(buf, ctx) } - fn to_owned_message(&self) -> super::super::ServiceOptions { + fn to_owned_message( + &self, + ) -> ::core::result::Result { self.to_owned_from_source(None) } #[allow(clippy::useless_conversion, clippy::needless_update)] fn to_owned_from_source( &self, __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, - ) -> super::super::ServiceOptions { + ) -> ::core::result::Result { #[allow(unused_imports)] use ::buffa::alloc::string::ToString as _; let _ = __buffa_src; - super::super::ServiceOptions { + ::core::result::Result::Ok(super::super::ServiceOptions { features: match self.features.as_option() { Some(v) => { ::buffa::MessageField::< super::super::FeatureSet, - >::some(v.to_owned_from_source(__buffa_src)) + >::some(v.to_owned_from_source(__buffa_src)?) } None => ::buffa::MessageField::none(), }, @@ -12681,14 +12937,10 @@ impl<'a> ::buffa::MessageView<'a> for ServiceOptionsView<'a> { .uninterpreted_option .iter() .map(|v| v.to_owned_from_source(__buffa_src)) - .collect(), - __buffa_unknown_fields: self - .__buffa_unknown_fields - .to_owned() - .unwrap_or_default() - .into(), + .collect::<::core::result::Result<_, ::buffa::DecodeError>>()?, + __buffa_unknown_fields: self.__buffa_unknown_fields.to_owned()?.into(), ..::core::default::Default::default() - } + }) } } impl<'a> ::buffa::ViewEncode<'a> for ServiceOptionsView<'a> { @@ -12870,8 +13122,14 @@ impl ServiceOptionsOwnedView { self.0.reborrow() } /// Convert to the owned message type. - #[must_use] - pub fn to_owned_message(&self) -> super::super::ServiceOptions { + /// + /// # 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 { self.0.to_owned_message() } /// The underlying bytes buffer. @@ -12992,20 +13250,22 @@ pub struct MethodOptionsView<'a> { pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, } impl<'a> MethodOptionsView<'a> { - /// Decode from `buf`, enforcing a recursion depth limit for nested messages. + /// Decode from `buf` under the limits carried by `ctx` (recursion + /// depth and the shared unknown-field allowance). /// - /// Called by [`::buffa::MessageView::decode_view`] with [`::buffa::RECURSION_LIMIT`] - /// and by generated sub-message decode arms with `depth - 1`. + /// Called by [`::buffa::MessageView::decode_view`] with a fresh + /// default context and by generated sub-message decode arms with + /// `ctx.descend()?`. /// /// **Not part of the public API.** Named with a leading underscore to /// signal that it is for generated-code use only. #[doc(hidden)] - pub fn _decode_depth( + pub fn _decode_ctx( buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result { let mut view = Self::default(); - view._merge_into_view(buf, depth)?; + view._merge_into_view(buf, ctx)?; ::core::result::Result::Ok(view) } /// Merge fields from `buf` into this view (proto merge semantics). @@ -13019,9 +13279,9 @@ impl<'a> MethodOptionsView<'a> { pub fn _merge_into_view( &mut self, buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result<(), ::buffa::DecodeError> { - let _ = depth; + let _ = ctx; #[allow(unused_variables)] let view = self; let mut cur: &'a [u8] = buf; @@ -13054,7 +13314,8 @@ impl<'a> MethodOptionsView<'a> { view.idempotency_level = Some(__v); } else { let __span_len = before_tag.len() - cur.len(); - view.__buffa_unknown_fields.push_raw(&before_tag[..__span_len]); + view.__buffa_unknown_fields + .push_record(before_tag, __span_len, ctx)?; } } 35u32 => { @@ -13065,17 +13326,15 @@ impl<'a> MethodOptionsView<'a> { actual: tag.wire_type() as u8, }); } - if depth == 0 { - return Err(::buffa::DecodeError::RecursionLimitExceeded); - } + let __sub_ctx = ctx.descend()?; let sub = ::buffa::types::borrow_bytes(&mut cur)?; match view.features.as_mut() { - Some(existing) => existing._merge_into_view(sub, depth - 1)?, + Some(existing) => existing._merge_into_view(sub, __sub_ctx)?, None => { view.features = ::buffa::MessageFieldView::set( - super::super::__buffa::view::FeatureSetView::_decode_depth( + super::super::__buffa::view::FeatureSetView::_decode_ctx( sub, - depth - 1, + __sub_ctx, )?, ); } @@ -13089,22 +13348,20 @@ impl<'a> MethodOptionsView<'a> { actual: tag.wire_type() as u8, }); } - if depth == 0 { - return Err(::buffa::DecodeError::RecursionLimitExceeded); - } + let __sub_ctx = ctx.descend()?; let sub = ::buffa::types::borrow_bytes(&mut cur)?; view.uninterpreted_option .push( - super::super::__buffa::view::UninterpretedOptionView::_decode_depth( + super::super::__buffa::view::UninterpretedOptionView::_decode_ctx( sub, - depth - 1, + __sub_ctx, )?, ); } _ => { - ::buffa::encoding::skip_field_depth(tag, &mut cur, depth)?; + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; let span_len = before_tag.len() - cur.len(); - view.__buffa_unknown_fields.push_raw(&before_tag[..span_len]); + view.__buffa_unknown_fields.push_record(before_tag, span_len, ctx)?; } } } @@ -13114,33 +13371,39 @@ impl<'a> MethodOptionsView<'a> { impl<'a> ::buffa::MessageView<'a> for MethodOptionsView<'a> { type Owned = super::super::MethodOptions; fn decode_view(buf: &'a [u8]) -> ::core::result::Result { - Self::_decode_depth(buf, ::buffa::RECURSION_LIMIT) + let __limit = ::core::cell::Cell::new(::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT); + Self::_decode_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit), + ) } - fn decode_view_with_limit( + fn decode_view_with_ctx( buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result { - Self::_decode_depth(buf, depth) + Self::_decode_ctx(buf, ctx) } - fn to_owned_message(&self) -> super::super::MethodOptions { + fn to_owned_message( + &self, + ) -> ::core::result::Result { self.to_owned_from_source(None) } #[allow(clippy::useless_conversion, clippy::needless_update)] fn to_owned_from_source( &self, __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, - ) -> super::super::MethodOptions { + ) -> ::core::result::Result { #[allow(unused_imports)] use ::buffa::alloc::string::ToString as _; let _ = __buffa_src; - super::super::MethodOptions { + ::core::result::Result::Ok(super::super::MethodOptions { deprecated: self.deprecated, idempotency_level: self.idempotency_level, features: match self.features.as_option() { Some(v) => { ::buffa::MessageField::< super::super::FeatureSet, - >::some(v.to_owned_from_source(__buffa_src)) + >::some(v.to_owned_from_source(__buffa_src)?) } None => ::buffa::MessageField::none(), }, @@ -13148,14 +13411,10 @@ impl<'a> ::buffa::MessageView<'a> for MethodOptionsView<'a> { .uninterpreted_option .iter() .map(|v| v.to_owned_from_source(__buffa_src)) - .collect(), - __buffa_unknown_fields: self - .__buffa_unknown_fields - .to_owned() - .unwrap_or_default() - .into(), + .collect::<::core::result::Result<_, ::buffa::DecodeError>>()?, + __buffa_unknown_fields: self.__buffa_unknown_fields.to_owned()?.into(), ..::core::default::Default::default() - } + }) } } impl<'a> ::buffa::ViewEncode<'a> for MethodOptionsView<'a> { @@ -13355,8 +13614,14 @@ impl MethodOptionsOwnedView { self.0.reborrow() } /// Convert to the owned message type. - #[must_use] - pub fn to_owned_message(&self) -> super::super::MethodOptions { + /// + /// # 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 { self.0.to_owned_message() } /// The underlying bytes buffer. @@ -13478,20 +13743,22 @@ pub struct UninterpretedOptionView<'a> { pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, } impl<'a> UninterpretedOptionView<'a> { - /// Decode from `buf`, enforcing a recursion depth limit for nested messages. + /// Decode from `buf` under the limits carried by `ctx` (recursion + /// depth and the shared unknown-field allowance). /// - /// Called by [`::buffa::MessageView::decode_view`] with [`::buffa::RECURSION_LIMIT`] - /// and by generated sub-message decode arms with `depth - 1`. + /// Called by [`::buffa::MessageView::decode_view`] with a fresh + /// default context and by generated sub-message decode arms with + /// `ctx.descend()?`. /// /// **Not part of the public API.** Named with a leading underscore to /// signal that it is for generated-code use only. #[doc(hidden)] - pub fn _decode_depth( + pub fn _decode_ctx( buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result { let mut view = Self::default(); - view._merge_into_view(buf, depth)?; + view._merge_into_view(buf, ctx)?; ::core::result::Result::Ok(view) } /// Merge fields from `buf` into this view (proto merge semantics). @@ -13505,9 +13772,9 @@ impl<'a> UninterpretedOptionView<'a> { pub fn _merge_into_view( &mut self, buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result<(), ::buffa::DecodeError> { - let _ = depth; + let _ = ctx; #[allow(unused_variables)] let view = self; let mut cur: &'a [u8] = buf; @@ -13587,22 +13854,20 @@ impl<'a> UninterpretedOptionView<'a> { actual: tag.wire_type() as u8, }); } - if depth == 0 { - return Err(::buffa::DecodeError::RecursionLimitExceeded); - } + let __sub_ctx = ctx.descend()?; let sub = ::buffa::types::borrow_bytes(&mut cur)?; view.name .push( - super::super::__buffa::view::uninterpreted_option::NamePartView::_decode_depth( + super::super::__buffa::view::uninterpreted_option::NamePartView::_decode_ctx( sub, - depth - 1, + __sub_ctx, )?, ); } _ => { - ::buffa::encoding::skip_field_depth(tag, &mut cur, depth)?; + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; let span_len = before_tag.len() - cur.len(); - view.__buffa_unknown_fields.push_raw(&before_tag[..span_len]); + view.__buffa_unknown_fields.push_record(before_tag, span_len, ctx)?; } } } @@ -13612,44 +13877,52 @@ impl<'a> UninterpretedOptionView<'a> { impl<'a> ::buffa::MessageView<'a> for UninterpretedOptionView<'a> { type Owned = super::super::UninterpretedOption; fn decode_view(buf: &'a [u8]) -> ::core::result::Result { - Self::_decode_depth(buf, ::buffa::RECURSION_LIMIT) + let __limit = ::core::cell::Cell::new(::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT); + Self::_decode_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit), + ) } - fn decode_view_with_limit( + fn decode_view_with_ctx( buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result { - Self::_decode_depth(buf, depth) + Self::_decode_ctx(buf, ctx) } - fn to_owned_message(&self) -> super::super::UninterpretedOption { + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::UninterpretedOption, + ::buffa::DecodeError, + > { self.to_owned_from_source(None) } #[allow(clippy::useless_conversion, clippy::needless_update)] fn to_owned_from_source( &self, __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, - ) -> super::super::UninterpretedOption { + ) -> ::core::result::Result< + super::super::UninterpretedOption, + ::buffa::DecodeError, + > { #[allow(unused_imports)] use ::buffa::alloc::string::ToString as _; let _ = __buffa_src; - super::super::UninterpretedOption { + ::core::result::Result::Ok(super::super::UninterpretedOption { name: self .name .iter() .map(|v| v.to_owned_from_source(__buffa_src)) - .collect(), + .collect::<::core::result::Result<_, ::buffa::DecodeError>>()?, identifier_value: self.identifier_value.map(|s| s.to_string()), positive_int_value: self.positive_int_value, negative_int_value: self.negative_int_value, double_value: self.double_value, string_value: self.string_value.map(|b| (b).to_vec()), aggregate_value: self.aggregate_value.map(|s| s.to_string()), - __buffa_unknown_fields: self - .__buffa_unknown_fields - .to_owned() - .unwrap_or_default() - .into(), + __buffa_unknown_fields: self.__buffa_unknown_fields.to_owned()?.into(), ..::core::default::Default::default() - } + }) } } impl<'a> ::buffa::ViewEncode<'a> for UninterpretedOptionView<'a> { @@ -13911,8 +14184,17 @@ impl UninterpretedOptionOwnedView { self.0.reborrow() } /// Convert to the owned message type. - #[must_use] - pub fn to_owned_message(&self) -> super::super::UninterpretedOption { + /// + /// # 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, + > { self.0.to_owned_message() } /// The underlying bytes buffer. @@ -14017,20 +14299,22 @@ pub mod uninterpreted_option { pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, } impl<'a> NamePartView<'a> { - /// Decode from `buf`, enforcing a recursion depth limit for nested messages. + /// Decode from `buf` under the limits carried by `ctx` (recursion + /// depth and the shared unknown-field allowance). /// - /// Called by [`::buffa::MessageView::decode_view`] with [`::buffa::RECURSION_LIMIT`] - /// and by generated sub-message decode arms with `depth - 1`. + /// Called by [`::buffa::MessageView::decode_view`] with a fresh + /// default context and by generated sub-message decode arms with + /// `ctx.descend()?`. /// /// **Not part of the public API.** Named with a leading underscore to /// signal that it is for generated-code use only. #[doc(hidden)] - pub fn _decode_depth( + pub fn _decode_ctx( buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result { let mut view = Self::default(); - view._merge_into_view(buf, depth)?; + view._merge_into_view(buf, ctx)?; ::core::result::Result::Ok(view) } /// Merge fields from `buf` into this view (proto merge semantics). @@ -14044,9 +14328,9 @@ pub mod uninterpreted_option { pub fn _merge_into_view( &mut self, buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result<(), ::buffa::DecodeError> { - let _ = depth; + let _ = ctx; #[allow(unused_variables)] let view = self; let mut cur: &'a [u8] = buf; @@ -14077,9 +14361,10 @@ pub mod uninterpreted_option { view.is_extension = ::buffa::types::decode_bool(&mut cur)?; } _ => { - ::buffa::encoding::skip_field_depth(tag, &mut cur, depth)?; + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; let span_len = before_tag.len() - cur.len(); - view.__buffa_unknown_fields.push_raw(&before_tag[..span_len]); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; } } } @@ -14091,37 +14376,43 @@ pub mod uninterpreted_option { fn decode_view( buf: &'a [u8], ) -> ::core::result::Result { - Self::_decode_depth(buf, ::buffa::RECURSION_LIMIT) + let __limit = ::core::cell::Cell::new(::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT); + Self::_decode_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit), + ) } - fn decode_view_with_limit( + fn decode_view_with_ctx( buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result { - Self::_decode_depth(buf, depth) + Self::_decode_ctx(buf, ctx) } fn to_owned_message( &self, - ) -> super::super::super::uninterpreted_option::NamePart { + ) -> ::core::result::Result< + super::super::super::uninterpreted_option::NamePart, + ::buffa::DecodeError, + > { self.to_owned_from_source(None) } #[allow(clippy::useless_conversion, clippy::needless_update)] fn to_owned_from_source( &self, __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, - ) -> super::super::super::uninterpreted_option::NamePart { + ) -> ::core::result::Result< + super::super::super::uninterpreted_option::NamePart, + ::buffa::DecodeError, + > { #[allow(unused_imports)] use ::buffa::alloc::string::ToString as _; let _ = __buffa_src; - super::super::super::uninterpreted_option::NamePart { + ::core::result::Result::Ok(super::super::super::uninterpreted_option::NamePart { name_part: self.name_part.to_string(), is_extension: self.is_extension, - __buffa_unknown_fields: self - .__buffa_unknown_fields - .to_owned() - .unwrap_or_default() - .into(), + __buffa_unknown_fields: self.__buffa_unknown_fields.to_owned()?.into(), ..::core::default::Default::default() - } + }) } } impl<'a> ::buffa::ViewEncode<'a> for NamePartView<'a> { @@ -14265,10 +14556,17 @@ pub mod uninterpreted_option { self.0.reborrow() } /// Convert to the owned message type. - #[must_use] + /// + /// # 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, - ) -> super::super::super::uninterpreted_option::NamePart { + ) -> ::core::result::Result< + super::super::super::uninterpreted_option::NamePart, + ::buffa::DecodeError, + > { self.0.to_owned_message() } /// The underlying bytes buffer. @@ -14365,20 +14663,22 @@ pub struct FeatureSetView<'a> { pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, } impl<'a> FeatureSetView<'a> { - /// Decode from `buf`, enforcing a recursion depth limit for nested messages. + /// Decode from `buf` under the limits carried by `ctx` (recursion + /// depth and the shared unknown-field allowance). /// - /// Called by [`::buffa::MessageView::decode_view`] with [`::buffa::RECURSION_LIMIT`] - /// and by generated sub-message decode arms with `depth - 1`. + /// Called by [`::buffa::MessageView::decode_view`] with a fresh + /// default context and by generated sub-message decode arms with + /// `ctx.descend()?`. /// /// **Not part of the public API.** Named with a leading underscore to /// signal that it is for generated-code use only. #[doc(hidden)] - pub fn _decode_depth( + pub fn _decode_ctx( buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result { let mut view = Self::default(); - view._merge_into_view(buf, depth)?; + view._merge_into_view(buf, ctx)?; ::core::result::Result::Ok(view) } /// Merge fields from `buf` into this view (proto merge semantics). @@ -14392,9 +14692,9 @@ impl<'a> FeatureSetView<'a> { pub fn _merge_into_view( &mut self, buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result<(), ::buffa::DecodeError> { - let _ = depth; + let _ = ctx; #[allow(unused_variables)] let view = self; let mut cur: &'a [u8] = buf; @@ -14417,7 +14717,8 @@ impl<'a> FeatureSetView<'a> { view.field_presence = Some(__v); } else { let __span_len = before_tag.len() - cur.len(); - view.__buffa_unknown_fields.push_raw(&before_tag[..__span_len]); + view.__buffa_unknown_fields + .push_record(before_tag, __span_len, ctx)?; } } 2u32 => { @@ -14435,7 +14736,8 @@ impl<'a> FeatureSetView<'a> { view.enum_type = Some(__v); } else { let __span_len = before_tag.len() - cur.len(); - view.__buffa_unknown_fields.push_raw(&before_tag[..__span_len]); + view.__buffa_unknown_fields + .push_record(before_tag, __span_len, ctx)?; } } 3u32 => { @@ -14453,7 +14755,8 @@ impl<'a> FeatureSetView<'a> { view.repeated_field_encoding = Some(__v); } else { let __span_len = before_tag.len() - cur.len(); - view.__buffa_unknown_fields.push_raw(&before_tag[..__span_len]); + view.__buffa_unknown_fields + .push_record(before_tag, __span_len, ctx)?; } } 4u32 => { @@ -14471,7 +14774,8 @@ impl<'a> FeatureSetView<'a> { view.utf8_validation = Some(__v); } else { let __span_len = before_tag.len() - cur.len(); - view.__buffa_unknown_fields.push_raw(&before_tag[..__span_len]); + view.__buffa_unknown_fields + .push_record(before_tag, __span_len, ctx)?; } } 5u32 => { @@ -14489,7 +14793,8 @@ impl<'a> FeatureSetView<'a> { view.message_encoding = Some(__v); } else { let __span_len = before_tag.len() - cur.len(); - view.__buffa_unknown_fields.push_raw(&before_tag[..__span_len]); + view.__buffa_unknown_fields + .push_record(before_tag, __span_len, ctx)?; } } 6u32 => { @@ -14507,7 +14812,8 @@ impl<'a> FeatureSetView<'a> { view.json_format = Some(__v); } else { let __span_len = before_tag.len() - cur.len(); - view.__buffa_unknown_fields.push_raw(&before_tag[..__span_len]); + view.__buffa_unknown_fields + .push_record(before_tag, __span_len, ctx)?; } } 7u32 => { @@ -14525,7 +14831,8 @@ impl<'a> FeatureSetView<'a> { view.enforce_naming_style = Some(__v); } else { let __span_len = before_tag.len() - cur.len(); - view.__buffa_unknown_fields.push_raw(&before_tag[..__span_len]); + view.__buffa_unknown_fields + .push_record(before_tag, __span_len, ctx)?; } } 8u32 => { @@ -14543,13 +14850,14 @@ impl<'a> FeatureSetView<'a> { view.default_symbol_visibility = Some(__v); } else { let __span_len = before_tag.len() - cur.len(); - view.__buffa_unknown_fields.push_raw(&before_tag[..__span_len]); + view.__buffa_unknown_fields + .push_record(before_tag, __span_len, ctx)?; } } _ => { - ::buffa::encoding::skip_field_depth(tag, &mut cur, depth)?; + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; let span_len = before_tag.len() - cur.len(); - view.__buffa_unknown_fields.push_raw(&before_tag[..span_len]); + view.__buffa_unknown_fields.push_record(before_tag, span_len, ctx)?; } } } @@ -14559,26 +14867,32 @@ impl<'a> FeatureSetView<'a> { impl<'a> ::buffa::MessageView<'a> for FeatureSetView<'a> { type Owned = super::super::FeatureSet; fn decode_view(buf: &'a [u8]) -> ::core::result::Result { - Self::_decode_depth(buf, ::buffa::RECURSION_LIMIT) + let __limit = ::core::cell::Cell::new(::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT); + Self::_decode_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit), + ) } - fn decode_view_with_limit( + fn decode_view_with_ctx( buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result { - Self::_decode_depth(buf, depth) + Self::_decode_ctx(buf, ctx) } - fn to_owned_message(&self) -> super::super::FeatureSet { + fn to_owned_message( + &self, + ) -> ::core::result::Result { self.to_owned_from_source(None) } #[allow(clippy::useless_conversion, clippy::needless_update)] fn to_owned_from_source( &self, __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, - ) -> super::super::FeatureSet { + ) -> ::core::result::Result { #[allow(unused_imports)] use ::buffa::alloc::string::ToString as _; let _ = __buffa_src; - super::super::FeatureSet { + ::core::result::Result::Ok(super::super::FeatureSet { field_presence: self.field_presence, enum_type: self.enum_type, repeated_field_encoding: self.repeated_field_encoding, @@ -14587,13 +14901,9 @@ impl<'a> ::buffa::MessageView<'a> for FeatureSetView<'a> { json_format: self.json_format, enforce_naming_style: self.enforce_naming_style, default_symbol_visibility: self.default_symbol_visibility, - __buffa_unknown_fields: self - .__buffa_unknown_fields - .to_owned() - .unwrap_or_default() - .into(), + __buffa_unknown_fields: self.__buffa_unknown_fields.to_owned()?.into(), ..::core::default::Default::default() - } + }) } } impl<'a> ::buffa::ViewEncode<'a> for FeatureSetView<'a> { @@ -14882,8 +15192,14 @@ impl FeatureSetOwnedView { self.0.reborrow() } /// Convert to the owned message type. - #[must_use] - pub fn to_owned_message(&self) -> super::super::FeatureSet { + /// + /// # 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 { self.0.to_owned_message() } /// The underlying bytes buffer. @@ -14994,20 +15310,22 @@ pub mod feature_set { pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, } impl<'a> VisibilityFeatureView<'a> { - /// Decode from `buf`, enforcing a recursion depth limit for nested messages. + /// Decode from `buf` under the limits carried by `ctx` (recursion + /// depth and the shared unknown-field allowance). /// - /// Called by [`::buffa::MessageView::decode_view`] with [`::buffa::RECURSION_LIMIT`] - /// and by generated sub-message decode arms with `depth - 1`. + /// Called by [`::buffa::MessageView::decode_view`] with a fresh + /// default context and by generated sub-message decode arms with + /// `ctx.descend()?`. /// /// **Not part of the public API.** Named with a leading underscore to /// signal that it is for generated-code use only. #[doc(hidden)] - pub fn _decode_depth( + pub fn _decode_ctx( buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result { let mut view = Self::default(); - view._merge_into_view(buf, depth)?; + view._merge_into_view(buf, ctx)?; ::core::result::Result::Ok(view) } /// Merge fields from `buf` into this view (proto merge semantics). @@ -15021,9 +15339,9 @@ pub mod feature_set { pub fn _merge_into_view( &mut self, buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result<(), ::buffa::DecodeError> { - let _ = depth; + let _ = ctx; #[allow(unused_variables)] let view = self; let mut cur: &'a [u8] = buf; @@ -15032,9 +15350,10 @@ pub mod feature_set { let tag = ::buffa::encoding::Tag::decode(&mut cur)?; match tag.field_number() { _ => { - ::buffa::encoding::skip_field_depth(tag, &mut cur, depth)?; + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; let span_len = before_tag.len() - cur.len(); - view.__buffa_unknown_fields.push_raw(&before_tag[..span_len]); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; } } } @@ -15046,35 +15365,41 @@ pub mod feature_set { fn decode_view( buf: &'a [u8], ) -> ::core::result::Result { - Self::_decode_depth(buf, ::buffa::RECURSION_LIMIT) + let __limit = ::core::cell::Cell::new(::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT); + Self::_decode_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit), + ) } - fn decode_view_with_limit( + fn decode_view_with_ctx( buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result { - Self::_decode_depth(buf, depth) + Self::_decode_ctx(buf, ctx) } fn to_owned_message( &self, - ) -> super::super::super::feature_set::VisibilityFeature { + ) -> ::core::result::Result< + super::super::super::feature_set::VisibilityFeature, + ::buffa::DecodeError, + > { self.to_owned_from_source(None) } #[allow(clippy::useless_conversion, clippy::needless_update)] fn to_owned_from_source( &self, __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, - ) -> super::super::super::feature_set::VisibilityFeature { + ) -> ::core::result::Result< + super::super::super::feature_set::VisibilityFeature, + ::buffa::DecodeError, + > { #[allow(unused_imports)] use ::buffa::alloc::string::ToString as _; let _ = __buffa_src; - super::super::super::feature_set::VisibilityFeature { - __buffa_unknown_fields: self - .__buffa_unknown_fields - .to_owned() - .unwrap_or_default() - .into(), + ::core::result::Result::Ok(super::super::super::feature_set::VisibilityFeature { + __buffa_unknown_fields: self.__buffa_unknown_fields.to_owned()?.into(), ..::core::default::Default::default() - } + }) } } impl<'a> ::buffa::ViewEncode<'a> for VisibilityFeatureView<'a> { @@ -15205,10 +15530,17 @@ pub mod feature_set { self.0.reborrow() } /// Convert to the owned message type. - #[must_use] + /// + /// # 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, - ) -> super::super::super::feature_set::VisibilityFeature { + ) -> ::core::result::Result< + super::super::super::feature_set::VisibilityFeature, + ::buffa::DecodeError, + > { self.0.to_owned_message() } /// The underlying bytes buffer. @@ -15281,20 +15613,22 @@ pub struct FeatureSetDefaultsView<'a> { pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, } impl<'a> FeatureSetDefaultsView<'a> { - /// Decode from `buf`, enforcing a recursion depth limit for nested messages. + /// Decode from `buf` under the limits carried by `ctx` (recursion + /// depth and the shared unknown-field allowance). /// - /// Called by [`::buffa::MessageView::decode_view`] with [`::buffa::RECURSION_LIMIT`] - /// and by generated sub-message decode arms with `depth - 1`. + /// Called by [`::buffa::MessageView::decode_view`] with a fresh + /// default context and by generated sub-message decode arms with + /// `ctx.descend()?`. /// /// **Not part of the public API.** Named with a leading underscore to /// signal that it is for generated-code use only. #[doc(hidden)] - pub fn _decode_depth( + pub fn _decode_ctx( buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result { let mut view = Self::default(); - view._merge_into_view(buf, depth)?; + view._merge_into_view(buf, ctx)?; ::core::result::Result::Ok(view) } /// Merge fields from `buf` into this view (proto merge semantics). @@ -15308,9 +15642,9 @@ impl<'a> FeatureSetDefaultsView<'a> { pub fn _merge_into_view( &mut self, buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result<(), ::buffa::DecodeError> { - let _ = depth; + let _ = ctx; #[allow(unused_variables)] let view = self; let mut cur: &'a [u8] = buf; @@ -15333,7 +15667,8 @@ impl<'a> FeatureSetDefaultsView<'a> { view.minimum_edition = Some(__v); } else { let __span_len = before_tag.len() - cur.len(); - view.__buffa_unknown_fields.push_raw(&before_tag[..__span_len]); + view.__buffa_unknown_fields + .push_record(before_tag, __span_len, ctx)?; } } 5u32 => { @@ -15351,7 +15686,8 @@ impl<'a> FeatureSetDefaultsView<'a> { view.maximum_edition = Some(__v); } else { let __span_len = before_tag.len() - cur.len(); - view.__buffa_unknown_fields.push_raw(&before_tag[..__span_len]); + view.__buffa_unknown_fields + .push_record(before_tag, __span_len, ctx)?; } } 1u32 => { @@ -15362,22 +15698,20 @@ impl<'a> FeatureSetDefaultsView<'a> { actual: tag.wire_type() as u8, }); } - if depth == 0 { - return Err(::buffa::DecodeError::RecursionLimitExceeded); - } + let __sub_ctx = ctx.descend()?; let sub = ::buffa::types::borrow_bytes(&mut cur)?; view.defaults .push( - super::super::__buffa::view::feature_set_defaults::FeatureSetEditionDefaultView::_decode_depth( + super::super::__buffa::view::feature_set_defaults::FeatureSetEditionDefaultView::_decode_ctx( sub, - depth - 1, + __sub_ctx, )?, ); } _ => { - ::buffa::encoding::skip_field_depth(tag, &mut cur, depth)?; + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; let span_len = before_tag.len() - cur.len(); - view.__buffa_unknown_fields.push_raw(&before_tag[..span_len]); + view.__buffa_unknown_fields.push_record(before_tag, span_len, ctx)?; } } } @@ -15387,40 +15721,42 @@ impl<'a> FeatureSetDefaultsView<'a> { impl<'a> ::buffa::MessageView<'a> for FeatureSetDefaultsView<'a> { type Owned = super::super::FeatureSetDefaults; fn decode_view(buf: &'a [u8]) -> ::core::result::Result { - Self::_decode_depth(buf, ::buffa::RECURSION_LIMIT) + let __limit = ::core::cell::Cell::new(::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT); + Self::_decode_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit), + ) } - fn decode_view_with_limit( + fn decode_view_with_ctx( buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result { - Self::_decode_depth(buf, depth) + Self::_decode_ctx(buf, ctx) } - fn to_owned_message(&self) -> super::super::FeatureSetDefaults { + fn to_owned_message( + &self, + ) -> ::core::result::Result { self.to_owned_from_source(None) } #[allow(clippy::useless_conversion, clippy::needless_update)] fn to_owned_from_source( &self, __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, - ) -> super::super::FeatureSetDefaults { + ) -> ::core::result::Result { #[allow(unused_imports)] use ::buffa::alloc::string::ToString as _; let _ = __buffa_src; - super::super::FeatureSetDefaults { + ::core::result::Result::Ok(super::super::FeatureSetDefaults { defaults: self .defaults .iter() .map(|v| v.to_owned_from_source(__buffa_src)) - .collect(), + .collect::<::core::result::Result<_, ::buffa::DecodeError>>()?, minimum_edition: self.minimum_edition, maximum_edition: self.maximum_edition, - __buffa_unknown_fields: self - .__buffa_unknown_fields - .to_owned() - .unwrap_or_default() - .into(), + __buffa_unknown_fields: self.__buffa_unknown_fields.to_owned()?.into(), ..::core::default::Default::default() - } + }) } } impl<'a> ::buffa::ViewEncode<'a> for FeatureSetDefaultsView<'a> { @@ -15611,8 +15947,14 @@ impl FeatureSetDefaultsOwnedView { self.0.reborrow() } /// Convert to the owned message type. - #[must_use] - pub fn to_owned_message(&self) -> super::super::FeatureSetDefaults { + /// + /// # 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 { self.0.to_owned_message() } /// The underlying bytes buffer. @@ -15711,20 +16053,22 @@ pub mod feature_set_defaults { pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, } impl<'a> FeatureSetEditionDefaultView<'a> { - /// Decode from `buf`, enforcing a recursion depth limit for nested messages. + /// Decode from `buf` under the limits carried by `ctx` (recursion + /// depth and the shared unknown-field allowance). /// - /// Called by [`::buffa::MessageView::decode_view`] with [`::buffa::RECURSION_LIMIT`] - /// and by generated sub-message decode arms with `depth - 1`. + /// Called by [`::buffa::MessageView::decode_view`] with a fresh + /// default context and by generated sub-message decode arms with + /// `ctx.descend()?`. /// /// **Not part of the public API.** Named with a leading underscore to /// signal that it is for generated-code use only. #[doc(hidden)] - pub fn _decode_depth( + pub fn _decode_ctx( buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result { let mut view = Self::default(); - view._merge_into_view(buf, depth)?; + view._merge_into_view(buf, ctx)?; ::core::result::Result::Ok(view) } /// Merge fields from `buf` into this view (proto merge semantics). @@ -15738,9 +16082,9 @@ pub mod feature_set_defaults { pub fn _merge_into_view( &mut self, buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result<(), ::buffa::DecodeError> { - let _ = depth; + let _ = ctx; #[allow(unused_variables)] let view = self; let mut cur: &'a [u8] = buf; @@ -15764,7 +16108,7 @@ pub mod feature_set_defaults { } else { let __span_len = before_tag.len() - cur.len(); view.__buffa_unknown_fields - .push_raw(&before_tag[..__span_len]); + .push_record(before_tag, __span_len, ctx)?; } } 4u32 => { @@ -15777,17 +16121,15 @@ pub mod feature_set_defaults { actual: tag.wire_type() as u8, }); } - if depth == 0 { - return Err(::buffa::DecodeError::RecursionLimitExceeded); - } + let __sub_ctx = ctx.descend()?; let sub = ::buffa::types::borrow_bytes(&mut cur)?; match view.overridable_features.as_mut() { - Some(existing) => existing._merge_into_view(sub, depth - 1)?, + Some(existing) => existing._merge_into_view(sub, __sub_ctx)?, None => { view.overridable_features = ::buffa::MessageFieldView::set( - super::super::super::__buffa::view::FeatureSetView::_decode_depth( + super::super::super::__buffa::view::FeatureSetView::_decode_ctx( sub, - depth - 1, + __sub_ctx, )?, ); } @@ -15803,26 +16145,25 @@ pub mod feature_set_defaults { actual: tag.wire_type() as u8, }); } - if depth == 0 { - return Err(::buffa::DecodeError::RecursionLimitExceeded); - } + let __sub_ctx = ctx.descend()?; let sub = ::buffa::types::borrow_bytes(&mut cur)?; match view.fixed_features.as_mut() { - Some(existing) => existing._merge_into_view(sub, depth - 1)?, + Some(existing) => existing._merge_into_view(sub, __sub_ctx)?, None => { view.fixed_features = ::buffa::MessageFieldView::set( - super::super::super::__buffa::view::FeatureSetView::_decode_depth( + super::super::super::__buffa::view::FeatureSetView::_decode_ctx( sub, - depth - 1, + __sub_ctx, )?, ); } } } _ => { - ::buffa::encoding::skip_field_depth(tag, &mut cur, depth)?; + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; let span_len = before_tag.len() - cur.len(); - view.__buffa_unknown_fields.push_raw(&before_tag[..span_len]); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; } } } @@ -15834,34 +16175,44 @@ pub mod feature_set_defaults { fn decode_view( buf: &'a [u8], ) -> ::core::result::Result { - Self::_decode_depth(buf, ::buffa::RECURSION_LIMIT) + let __limit = ::core::cell::Cell::new(::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT); + Self::_decode_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit), + ) } - fn decode_view_with_limit( + fn decode_view_with_ctx( buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result { - Self::_decode_depth(buf, depth) + Self::_decode_ctx(buf, ctx) } fn to_owned_message( &self, - ) -> super::super::super::feature_set_defaults::FeatureSetEditionDefault { + ) -> ::core::result::Result< + super::super::super::feature_set_defaults::FeatureSetEditionDefault, + ::buffa::DecodeError, + > { self.to_owned_from_source(None) } #[allow(clippy::useless_conversion, clippy::needless_update)] fn to_owned_from_source( &self, __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, - ) -> super::super::super::feature_set_defaults::FeatureSetEditionDefault { + ) -> ::core::result::Result< + super::super::super::feature_set_defaults::FeatureSetEditionDefault, + ::buffa::DecodeError, + > { #[allow(unused_imports)] use ::buffa::alloc::string::ToString as _; let _ = __buffa_src; - super::super::super::feature_set_defaults::FeatureSetEditionDefault { + ::core::result::Result::Ok(super::super::super::feature_set_defaults::FeatureSetEditionDefault { edition: self.edition, overridable_features: match self.overridable_features.as_option() { Some(v) => { ::buffa::MessageField::< super::super::super::FeatureSet, - >::some(v.to_owned_from_source(__buffa_src)) + >::some(v.to_owned_from_source(__buffa_src)?) } None => ::buffa::MessageField::none(), }, @@ -15869,17 +16220,13 @@ pub mod feature_set_defaults { Some(v) => { ::buffa::MessageField::< super::super::super::FeatureSet, - >::some(v.to_owned_from_source(__buffa_src)) + >::some(v.to_owned_from_source(__buffa_src)?) } None => ::buffa::MessageField::none(), }, - __buffa_unknown_fields: self - .__buffa_unknown_fields - .to_owned() - .unwrap_or_default() - .into(), + __buffa_unknown_fields: self.__buffa_unknown_fields.to_owned()?.into(), ..::core::default::Default::default() - } + }) } } impl<'a> ::buffa::ViewEncode<'a> for FeatureSetEditionDefaultView<'a> { @@ -16082,10 +16429,17 @@ pub mod feature_set_defaults { self.0.reborrow() } /// Convert to the owned message type. - #[must_use] + /// + /// # 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, - ) -> super::super::super::feature_set_defaults::FeatureSetEditionDefault { + ) -> ::core::result::Result< + super::super::super::feature_set_defaults::FeatureSetEditionDefault, + ::buffa::DecodeError, + > { self.0.to_owned_message() } /// The underlying bytes buffer. @@ -16223,20 +16577,22 @@ pub struct SourceCodeInfoView<'a> { pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, } impl<'a> SourceCodeInfoView<'a> { - /// Decode from `buf`, enforcing a recursion depth limit for nested messages. + /// Decode from `buf` under the limits carried by `ctx` (recursion + /// depth and the shared unknown-field allowance). /// - /// Called by [`::buffa::MessageView::decode_view`] with [`::buffa::RECURSION_LIMIT`] - /// and by generated sub-message decode arms with `depth - 1`. + /// Called by [`::buffa::MessageView::decode_view`] with a fresh + /// default context and by generated sub-message decode arms with + /// `ctx.descend()?`. /// /// **Not part of the public API.** Named with a leading underscore to /// signal that it is for generated-code use only. #[doc(hidden)] - pub fn _decode_depth( + pub fn _decode_ctx( buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result { let mut view = Self::default(); - view._merge_into_view(buf, depth)?; + view._merge_into_view(buf, ctx)?; ::core::result::Result::Ok(view) } /// Merge fields from `buf` into this view (proto merge semantics). @@ -16250,9 +16606,9 @@ impl<'a> SourceCodeInfoView<'a> { pub fn _merge_into_view( &mut self, buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result<(), ::buffa::DecodeError> { - let _ = depth; + let _ = ctx; #[allow(unused_variables)] let view = self; let mut cur: &'a [u8] = buf; @@ -16268,22 +16624,20 @@ impl<'a> SourceCodeInfoView<'a> { actual: tag.wire_type() as u8, }); } - if depth == 0 { - return Err(::buffa::DecodeError::RecursionLimitExceeded); - } + let __sub_ctx = ctx.descend()?; let sub = ::buffa::types::borrow_bytes(&mut cur)?; view.location .push( - super::super::__buffa::view::source_code_info::LocationView::_decode_depth( + super::super::__buffa::view::source_code_info::LocationView::_decode_ctx( sub, - depth - 1, + __sub_ctx, )?, ); } _ => { - ::buffa::encoding::skip_field_depth(tag, &mut cur, depth)?; + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; let span_len = before_tag.len() - cur.len(); - view.__buffa_unknown_fields.push_raw(&before_tag[..span_len]); + view.__buffa_unknown_fields.push_record(before_tag, span_len, ctx)?; } } } @@ -16293,38 +16647,40 @@ impl<'a> SourceCodeInfoView<'a> { impl<'a> ::buffa::MessageView<'a> for SourceCodeInfoView<'a> { type Owned = super::super::SourceCodeInfo; fn decode_view(buf: &'a [u8]) -> ::core::result::Result { - Self::_decode_depth(buf, ::buffa::RECURSION_LIMIT) + let __limit = ::core::cell::Cell::new(::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT); + Self::_decode_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit), + ) } - fn decode_view_with_limit( + fn decode_view_with_ctx( buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result { - Self::_decode_depth(buf, depth) + Self::_decode_ctx(buf, ctx) } - fn to_owned_message(&self) -> super::super::SourceCodeInfo { + fn to_owned_message( + &self, + ) -> ::core::result::Result { self.to_owned_from_source(None) } #[allow(clippy::useless_conversion, clippy::needless_update)] fn to_owned_from_source( &self, __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, - ) -> super::super::SourceCodeInfo { + ) -> ::core::result::Result { #[allow(unused_imports)] use ::buffa::alloc::string::ToString as _; let _ = __buffa_src; - super::super::SourceCodeInfo { + ::core::result::Result::Ok(super::super::SourceCodeInfo { location: self .location .iter() .map(|v| v.to_owned_from_source(__buffa_src)) - .collect(), - __buffa_unknown_fields: self - .__buffa_unknown_fields - .to_owned() - .unwrap_or_default() - .into(), + .collect::<::core::result::Result<_, ::buffa::DecodeError>>()?, + __buffa_unknown_fields: self.__buffa_unknown_fields.to_owned()?.into(), ..::core::default::Default::default() - } + }) } } impl<'a> ::buffa::ViewEncode<'a> for SourceCodeInfoView<'a> { @@ -16473,8 +16829,14 @@ impl SourceCodeInfoOwnedView { self.0.reborrow() } /// Convert to the owned message type. - #[must_use] - pub fn to_owned_message(&self) -> super::super::SourceCodeInfo { + /// + /// # 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 { self.0.to_owned_message() } /// The underlying bytes buffer. @@ -16677,20 +17039,22 @@ pub mod source_code_info { pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, } impl<'a> LocationView<'a> { - /// Decode from `buf`, enforcing a recursion depth limit for nested messages. + /// Decode from `buf` under the limits carried by `ctx` (recursion + /// depth and the shared unknown-field allowance). /// - /// Called by [`::buffa::MessageView::decode_view`] with [`::buffa::RECURSION_LIMIT`] - /// and by generated sub-message decode arms with `depth - 1`. + /// Called by [`::buffa::MessageView::decode_view`] with a fresh + /// default context and by generated sub-message decode arms with + /// `ctx.descend()?`. /// /// **Not part of the public API.** Named with a leading underscore to /// signal that it is for generated-code use only. #[doc(hidden)] - pub fn _decode_depth( + pub fn _decode_ctx( buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result { let mut view = Self::default(); - view._merge_into_view(buf, depth)?; + view._merge_into_view(buf, ctx)?; ::core::result::Result::Ok(view) } /// Merge fields from `buf` into this view (proto merge semantics). @@ -16704,9 +17068,9 @@ pub mod source_code_info { pub fn _merge_into_view( &mut self, buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result<(), ::buffa::DecodeError> { - let _ = depth; + let _ = ctx; #[allow(unused_variables)] let view = self; let mut cur: &'a [u8] = buf; @@ -16798,9 +17162,10 @@ pub mod source_code_info { .push(::buffa::types::borrow_str(&mut cur)?); } _ => { - ::buffa::encoding::skip_field_depth(tag, &mut cur, depth)?; + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; let span_len = before_tag.len() - cur.len(); - view.__buffa_unknown_fields.push_raw(&before_tag[..span_len]); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; } } } @@ -16812,26 +17177,38 @@ pub mod source_code_info { fn decode_view( buf: &'a [u8], ) -> ::core::result::Result { - Self::_decode_depth(buf, ::buffa::RECURSION_LIMIT) + let __limit = ::core::cell::Cell::new(::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT); + Self::_decode_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit), + ) } - fn decode_view_with_limit( + fn decode_view_with_ctx( buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result { - Self::_decode_depth(buf, depth) + Self::_decode_ctx(buf, ctx) } - fn to_owned_message(&self) -> super::super::super::source_code_info::Location { + fn to_owned_message( + &self, + ) -> ::core::result::Result< + super::super::super::source_code_info::Location, + ::buffa::DecodeError, + > { self.to_owned_from_source(None) } #[allow(clippy::useless_conversion, clippy::needless_update)] fn to_owned_from_source( &self, __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, - ) -> super::super::super::source_code_info::Location { + ) -> ::core::result::Result< + super::super::super::source_code_info::Location, + ::buffa::DecodeError, + > { #[allow(unused_imports)] use ::buffa::alloc::string::ToString as _; let _ = __buffa_src; - super::super::super::source_code_info::Location { + ::core::result::Result::Ok(super::super::super::source_code_info::Location { path: self.path.to_vec(), span: self.span.to_vec(), leading_comments: self.leading_comments.map(|s| s.to_string()), @@ -16841,13 +17218,9 @@ pub mod source_code_info { .iter() .map(|s| s.to_string()) .collect(), - __buffa_unknown_fields: self - .__buffa_unknown_fields - .to_owned() - .unwrap_or_default() - .into(), + __buffa_unknown_fields: self.__buffa_unknown_fields.to_owned()?.into(), ..::core::default::Default::default() - } + }) } } impl<'a> ::buffa::ViewEncode<'a> for LocationView<'a> { @@ -17096,10 +17469,17 @@ pub mod source_code_info { self.0.reborrow() } /// Convert to the owned message type. - #[must_use] + /// + /// # 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, - ) -> super::super::super::source_code_info::Location { + ) -> ::core::result::Result< + super::super::super::source_code_info::Location, + ::buffa::DecodeError, + > { self.0.to_owned_message() } /// The underlying bytes buffer. @@ -17270,20 +17650,22 @@ pub struct GeneratedCodeInfoView<'a> { pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, } impl<'a> GeneratedCodeInfoView<'a> { - /// Decode from `buf`, enforcing a recursion depth limit for nested messages. + /// Decode from `buf` under the limits carried by `ctx` (recursion + /// depth and the shared unknown-field allowance). /// - /// Called by [`::buffa::MessageView::decode_view`] with [`::buffa::RECURSION_LIMIT`] - /// and by generated sub-message decode arms with `depth - 1`. + /// Called by [`::buffa::MessageView::decode_view`] with a fresh + /// default context and by generated sub-message decode arms with + /// `ctx.descend()?`. /// /// **Not part of the public API.** Named with a leading underscore to /// signal that it is for generated-code use only. #[doc(hidden)] - pub fn _decode_depth( + pub fn _decode_ctx( buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result { let mut view = Self::default(); - view._merge_into_view(buf, depth)?; + view._merge_into_view(buf, ctx)?; ::core::result::Result::Ok(view) } /// Merge fields from `buf` into this view (proto merge semantics). @@ -17297,9 +17679,9 @@ impl<'a> GeneratedCodeInfoView<'a> { pub fn _merge_into_view( &mut self, buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result<(), ::buffa::DecodeError> { - let _ = depth; + let _ = ctx; #[allow(unused_variables)] let view = self; let mut cur: &'a [u8] = buf; @@ -17315,22 +17697,20 @@ impl<'a> GeneratedCodeInfoView<'a> { actual: tag.wire_type() as u8, }); } - if depth == 0 { - return Err(::buffa::DecodeError::RecursionLimitExceeded); - } + let __sub_ctx = ctx.descend()?; let sub = ::buffa::types::borrow_bytes(&mut cur)?; view.annotation .push( - super::super::__buffa::view::generated_code_info::AnnotationView::_decode_depth( + super::super::__buffa::view::generated_code_info::AnnotationView::_decode_ctx( sub, - depth - 1, + __sub_ctx, )?, ); } _ => { - ::buffa::encoding::skip_field_depth(tag, &mut cur, depth)?; + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; let span_len = before_tag.len() - cur.len(); - view.__buffa_unknown_fields.push_raw(&before_tag[..span_len]); + view.__buffa_unknown_fields.push_record(before_tag, span_len, ctx)?; } } } @@ -17340,38 +17720,40 @@ impl<'a> GeneratedCodeInfoView<'a> { impl<'a> ::buffa::MessageView<'a> for GeneratedCodeInfoView<'a> { type Owned = super::super::GeneratedCodeInfo; fn decode_view(buf: &'a [u8]) -> ::core::result::Result { - Self::_decode_depth(buf, ::buffa::RECURSION_LIMIT) + let __limit = ::core::cell::Cell::new(::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT); + Self::_decode_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit), + ) } - fn decode_view_with_limit( + fn decode_view_with_ctx( buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result { - Self::_decode_depth(buf, depth) + Self::_decode_ctx(buf, ctx) } - fn to_owned_message(&self) -> super::super::GeneratedCodeInfo { + fn to_owned_message( + &self, + ) -> ::core::result::Result { self.to_owned_from_source(None) } #[allow(clippy::useless_conversion, clippy::needless_update)] fn to_owned_from_source( &self, __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, - ) -> super::super::GeneratedCodeInfo { + ) -> ::core::result::Result { #[allow(unused_imports)] use ::buffa::alloc::string::ToString as _; let _ = __buffa_src; - super::super::GeneratedCodeInfo { + ::core::result::Result::Ok(super::super::GeneratedCodeInfo { annotation: self .annotation .iter() .map(|v| v.to_owned_from_source(__buffa_src)) - .collect(), - __buffa_unknown_fields: self - .__buffa_unknown_fields - .to_owned() - .unwrap_or_default() - .into(), + .collect::<::core::result::Result<_, ::buffa::DecodeError>>()?, + __buffa_unknown_fields: self.__buffa_unknown_fields.to_owned()?.into(), ..::core::default::Default::default() - } + }) } } impl<'a> ::buffa::ViewEncode<'a> for GeneratedCodeInfoView<'a> { @@ -17522,8 +17904,14 @@ impl GeneratedCodeInfoOwnedView { self.0.reborrow() } /// Convert to the owned message type. - #[must_use] - pub fn to_owned_message(&self) -> super::super::GeneratedCodeInfo { + /// + /// # 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 { self.0.to_owned_message() } /// The underlying bytes buffer. @@ -17613,20 +18001,22 @@ pub mod generated_code_info { pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, } impl<'a> AnnotationView<'a> { - /// Decode from `buf`, enforcing a recursion depth limit for nested messages. + /// Decode from `buf` under the limits carried by `ctx` (recursion + /// depth and the shared unknown-field allowance). /// - /// Called by [`::buffa::MessageView::decode_view`] with [`::buffa::RECURSION_LIMIT`] - /// and by generated sub-message decode arms with `depth - 1`. + /// Called by [`::buffa::MessageView::decode_view`] with a fresh + /// default context and by generated sub-message decode arms with + /// `ctx.descend()?`. /// /// **Not part of the public API.** Named with a leading underscore to /// signal that it is for generated-code use only. #[doc(hidden)] - pub fn _decode_depth( + pub fn _decode_ctx( buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result { let mut view = Self::default(); - view._merge_into_view(buf, depth)?; + view._merge_into_view(buf, ctx)?; ::core::result::Result::Ok(view) } /// Merge fields from `buf` into this view (proto merge semantics). @@ -17640,9 +18030,9 @@ pub mod generated_code_info { pub fn _merge_into_view( &mut self, buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result<(), ::buffa::DecodeError> { - let _ = depth; + let _ = ctx; #[allow(unused_variables)] let view = self; let mut cur: &'a [u8] = buf; @@ -17698,7 +18088,7 @@ pub mod generated_code_info { } else { let __span_len = before_tag.len() - cur.len(); view.__buffa_unknown_fields - .push_raw(&before_tag[..__span_len]); + .push_record(before_tag, __span_len, ctx)?; } } 1u32 => { @@ -17723,9 +18113,10 @@ pub mod generated_code_info { } } _ => { - ::buffa::encoding::skip_field_depth(tag, &mut cur, depth)?; + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; let span_len = before_tag.len() - cur.len(); - view.__buffa_unknown_fields.push_raw(&before_tag[..span_len]); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; } } } @@ -17737,40 +18128,46 @@ pub mod generated_code_info { fn decode_view( buf: &'a [u8], ) -> ::core::result::Result { - Self::_decode_depth(buf, ::buffa::RECURSION_LIMIT) + let __limit = ::core::cell::Cell::new(::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT); + Self::_decode_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit), + ) } - fn decode_view_with_limit( + fn decode_view_with_ctx( buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result { - Self::_decode_depth(buf, depth) + Self::_decode_ctx(buf, ctx) } fn to_owned_message( &self, - ) -> super::super::super::generated_code_info::Annotation { + ) -> ::core::result::Result< + super::super::super::generated_code_info::Annotation, + ::buffa::DecodeError, + > { self.to_owned_from_source(None) } #[allow(clippy::useless_conversion, clippy::needless_update)] fn to_owned_from_source( &self, __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, - ) -> super::super::super::generated_code_info::Annotation { + ) -> ::core::result::Result< + super::super::super::generated_code_info::Annotation, + ::buffa::DecodeError, + > { #[allow(unused_imports)] use ::buffa::alloc::string::ToString as _; let _ = __buffa_src; - super::super::super::generated_code_info::Annotation { + ::core::result::Result::Ok(super::super::super::generated_code_info::Annotation { path: self.path.to_vec(), source_file: self.source_file.map(|s| s.to_string()), begin: self.begin, end: self.end, semantic: self.semantic, - __buffa_unknown_fields: self - .__buffa_unknown_fields - .to_owned() - .unwrap_or_default() - .into(), + __buffa_unknown_fields: self.__buffa_unknown_fields.to_owned()?.into(), ..::core::default::Default::default() - } + }) } } impl<'a> ::buffa::ViewEncode<'a> for AnnotationView<'a> { @@ -18013,10 +18410,17 @@ pub mod generated_code_info { self.0.reborrow() } /// Convert to the owned message type. - #[must_use] + /// + /// # 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, - ) -> super::super::super::generated_code_info::Annotation { + ) -> ::core::result::Result< + super::super::super::generated_code_info::Annotation, + ::buffa::DecodeError, + > { self.0.to_owned_message() } /// The underlying bytes buffer. diff --git a/buffa-descriptor/src/generated/google.protobuf.descriptor.rs b/buffa-descriptor/src/generated/google.protobuf.descriptor.rs index a85ecf52..e0d6fcff 100644 --- a/buffa-descriptor/src/generated/google.protobuf.descriptor.rs +++ b/buffa-descriptor/src/generated/google.protobuf.descriptor.rs @@ -497,7 +497,7 @@ impl ::buffa::Message for FileDescriptorSet { &mut self, tag: ::buffa::encoding::Tag, buf: &mut impl ::buffa::bytes::Buf, - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result<(), ::buffa::DecodeError> { #[allow(unused_imports)] use ::buffa::bytes::Buf as _; @@ -513,12 +513,12 @@ impl ::buffa::Message for FileDescriptorSet { }); } let mut elem = ::core::default::Default::default(); - ::buffa::Message::merge_length_delimited(&mut elem, buf, depth)?; + ::buffa::Message::merge_length_delimited(&mut elem, buf, ctx)?; self.file.push(elem); } _ => { self.__buffa_unknown_fields - .push(::buffa::encoding::decode_unknown_field(tag, buf, depth)?); + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); } } ::core::result::Result::Ok(()) @@ -1209,7 +1209,7 @@ impl ::buffa::Message for FileDescriptorProto { &mut self, tag: ::buffa::encoding::Tag, buf: &mut impl ::buffa::bytes::Buf, - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result<(), ::buffa::DecodeError> { #[allow(unused_imports)] use ::buffa::bytes::Buf as _; @@ -1261,7 +1261,7 @@ impl ::buffa::Message for FileDescriptorProto { }); } let mut elem = ::core::default::Default::default(); - ::buffa::Message::merge_length_delimited(&mut elem, buf, depth)?; + ::buffa::Message::merge_length_delimited(&mut elem, buf, ctx)?; self.message_type.push(elem); } 5u32 => { @@ -1273,7 +1273,7 @@ impl ::buffa::Message for FileDescriptorProto { }); } let mut elem = ::core::default::Default::default(); - ::buffa::Message::merge_length_delimited(&mut elem, buf, depth)?; + ::buffa::Message::merge_length_delimited(&mut elem, buf, ctx)?; self.enum_type.push(elem); } 6u32 => { @@ -1285,7 +1285,7 @@ impl ::buffa::Message for FileDescriptorProto { }); } let mut elem = ::core::default::Default::default(); - ::buffa::Message::merge_length_delimited(&mut elem, buf, depth)?; + ::buffa::Message::merge_length_delimited(&mut elem, buf, ctx)?; self.service.push(elem); } 7u32 => { @@ -1297,7 +1297,7 @@ impl ::buffa::Message for FileDescriptorProto { }); } let mut elem = ::core::default::Default::default(); - ::buffa::Message::merge_length_delimited(&mut elem, buf, depth)?; + ::buffa::Message::merge_length_delimited(&mut elem, buf, ctx)?; self.extension.push(elem); } 8u32 => { @@ -1311,7 +1311,7 @@ impl ::buffa::Message for FileDescriptorProto { ::buffa::Message::merge_length_delimited( self.options.get_or_insert_default(), buf, - depth, + ctx, )?; } 9u32 => { @@ -1325,7 +1325,7 @@ impl ::buffa::Message for FileDescriptorProto { ::buffa::Message::merge_length_delimited( self.source_code_info.get_or_insert_default(), buf, - depth, + ctx, )?; } 10u32 => { @@ -1434,7 +1434,7 @@ impl ::buffa::Message for FileDescriptorProto { } _ => { self.__buffa_unknown_fields - .push(::buffa::encoding::decode_unknown_field(tag, buf, depth)?); + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); } } ::core::result::Result::Ok(()) @@ -2038,7 +2038,7 @@ impl ::buffa::Message for DescriptorProto { &mut self, tag: ::buffa::encoding::Tag, buf: &mut impl ::buffa::bytes::Buf, - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result<(), ::buffa::DecodeError> { #[allow(unused_imports)] use ::buffa::bytes::Buf as _; @@ -2067,7 +2067,7 @@ impl ::buffa::Message for DescriptorProto { }); } let mut elem = ::core::default::Default::default(); - ::buffa::Message::merge_length_delimited(&mut elem, buf, depth)?; + ::buffa::Message::merge_length_delimited(&mut elem, buf, ctx)?; self.field.push(elem); } 3u32 => { @@ -2079,7 +2079,7 @@ impl ::buffa::Message for DescriptorProto { }); } let mut elem = ::core::default::Default::default(); - ::buffa::Message::merge_length_delimited(&mut elem, buf, depth)?; + ::buffa::Message::merge_length_delimited(&mut elem, buf, ctx)?; self.nested_type.push(elem); } 4u32 => { @@ -2091,7 +2091,7 @@ impl ::buffa::Message for DescriptorProto { }); } let mut elem = ::core::default::Default::default(); - ::buffa::Message::merge_length_delimited(&mut elem, buf, depth)?; + ::buffa::Message::merge_length_delimited(&mut elem, buf, ctx)?; self.enum_type.push(elem); } 5u32 => { @@ -2103,7 +2103,7 @@ impl ::buffa::Message for DescriptorProto { }); } let mut elem = ::core::default::Default::default(); - ::buffa::Message::merge_length_delimited(&mut elem, buf, depth)?; + ::buffa::Message::merge_length_delimited(&mut elem, buf, ctx)?; self.extension_range.push(elem); } 6u32 => { @@ -2115,7 +2115,7 @@ impl ::buffa::Message for DescriptorProto { }); } let mut elem = ::core::default::Default::default(); - ::buffa::Message::merge_length_delimited(&mut elem, buf, depth)?; + ::buffa::Message::merge_length_delimited(&mut elem, buf, ctx)?; self.extension.push(elem); } 7u32 => { @@ -2129,7 +2129,7 @@ impl ::buffa::Message for DescriptorProto { ::buffa::Message::merge_length_delimited( self.options.get_or_insert_default(), buf, - depth, + ctx, )?; } 8u32 => { @@ -2141,7 +2141,7 @@ impl ::buffa::Message for DescriptorProto { }); } let mut elem = ::core::default::Default::default(); - ::buffa::Message::merge_length_delimited(&mut elem, buf, depth)?; + ::buffa::Message::merge_length_delimited(&mut elem, buf, ctx)?; self.oneof_decl.push(elem); } 9u32 => { @@ -2153,7 +2153,7 @@ impl ::buffa::Message for DescriptorProto { }); } let mut elem = ::core::default::Default::default(); - ::buffa::Message::merge_length_delimited(&mut elem, buf, depth)?; + ::buffa::Message::merge_length_delimited(&mut elem, buf, ctx)?; self.reserved_range.push(elem); } 10u32 => { @@ -2189,7 +2189,7 @@ impl ::buffa::Message for DescriptorProto { } _ => { self.__buffa_unknown_fields - .push(::buffa::encoding::decode_unknown_field(tag, buf, depth)?); + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); } } ::core::result::Result::Ok(()) @@ -2552,7 +2552,7 @@ pub mod descriptor_proto { &mut self, tag: ::buffa::encoding::Tag, buf: &mut impl ::buffa::bytes::Buf, - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result<(), ::buffa::DecodeError> { #[allow(unused_imports)] use ::buffa::bytes::Buf as _; @@ -2594,12 +2594,12 @@ pub mod descriptor_proto { ::buffa::Message::merge_length_delimited( self.options.get_or_insert_default(), buf, - depth, + ctx, )?; } _ => { self.__buffa_unknown_fields - .push(::buffa::encoding::decode_unknown_field(tag, buf, depth)?); + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); } } ::core::result::Result::Ok(()) @@ -2811,7 +2811,7 @@ pub mod descriptor_proto { &mut self, tag: ::buffa::encoding::Tag, buf: &mut impl ::buffa::bytes::Buf, - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result<(), ::buffa::DecodeError> { #[allow(unused_imports)] use ::buffa::bytes::Buf as _; @@ -2844,7 +2844,7 @@ pub mod descriptor_proto { } _ => { self.__buffa_unknown_fields - .push(::buffa::encoding::decode_unknown_field(tag, buf, depth)?); + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); } } ::core::result::Result::Ok(()) @@ -3129,7 +3129,7 @@ impl ::buffa::Message for ExtensionRangeOptions { &mut self, tag: ::buffa::encoding::Tag, buf: &mut impl ::buffa::bytes::Buf, - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result<(), ::buffa::DecodeError> { #[allow(unused_imports)] use ::buffa::bytes::Buf as _; @@ -3145,7 +3145,7 @@ impl ::buffa::Message for ExtensionRangeOptions { }); } let mut elem = ::core::default::Default::default(); - ::buffa::Message::merge_length_delimited(&mut elem, buf, depth)?; + ::buffa::Message::merge_length_delimited(&mut elem, buf, ctx)?; self.declaration.push(elem); } 3u32 => { @@ -3180,7 +3180,7 @@ impl ::buffa::Message for ExtensionRangeOptions { ::buffa::Message::merge_length_delimited( self.features.get_or_insert_default(), buf, - depth, + ctx, )?; } 999u32 => { @@ -3192,12 +3192,12 @@ impl ::buffa::Message for ExtensionRangeOptions { }); } let mut elem = ::core::default::Default::default(); - ::buffa::Message::merge_length_delimited(&mut elem, buf, depth)?; + ::buffa::Message::merge_length_delimited(&mut elem, buf, ctx)?; self.uninterpreted_option.push(elem); } _ => { self.__buffa_unknown_fields - .push(::buffa::encoding::decode_unknown_field(tag, buf, depth)?); + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); } } ::core::result::Result::Ok(()) @@ -3889,7 +3889,7 @@ pub mod extension_range_options { &mut self, tag: ::buffa::encoding::Tag, buf: &mut impl ::buffa::bytes::Buf, - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result<(), ::buffa::DecodeError> { #[allow(unused_imports)] use ::buffa::bytes::Buf as _; @@ -3964,7 +3964,7 @@ pub mod extension_range_options { } _ => { self.__buffa_unknown_fields - .push(::buffa::encoding::decode_unknown_field(tag, buf, depth)?); + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); } } ::core::result::Result::Ok(()) @@ -4514,7 +4514,7 @@ impl ::buffa::Message for FieldDescriptorProto { &mut self, tag: ::buffa::encoding::Tag, buf: &mut impl ::buffa::bytes::Buf, - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result<(), ::buffa::DecodeError> { #[allow(unused_imports)] use ::buffa::bytes::Buf as _; @@ -4644,7 +4644,7 @@ impl ::buffa::Message for FieldDescriptorProto { ::buffa::Message::merge_length_delimited( self.options.get_or_insert_default(), buf, - depth, + ctx, )?; } 9u32 => { @@ -4688,7 +4688,7 @@ impl ::buffa::Message for FieldDescriptorProto { } _ => { self.__buffa_unknown_fields - .push(::buffa::encoding::decode_unknown_field(tag, buf, depth)?); + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); } } ::core::result::Result::Ok(()) @@ -5416,7 +5416,7 @@ impl ::buffa::Message for OneofDescriptorProto { &mut self, tag: ::buffa::encoding::Tag, buf: &mut impl ::buffa::bytes::Buf, - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result<(), ::buffa::DecodeError> { #[allow(unused_imports)] use ::buffa::bytes::Buf as _; @@ -5447,12 +5447,12 @@ impl ::buffa::Message for OneofDescriptorProto { ::buffa::Message::merge_length_delimited( self.options.get_or_insert_default(), buf, - depth, + ctx, )?; } _ => { self.__buffa_unknown_fields - .push(::buffa::encoding::decode_unknown_field(tag, buf, depth)?); + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); } } ::core::result::Result::Ok(()) @@ -5776,7 +5776,7 @@ impl ::buffa::Message for EnumDescriptorProto { &mut self, tag: ::buffa::encoding::Tag, buf: &mut impl ::buffa::bytes::Buf, - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result<(), ::buffa::DecodeError> { #[allow(unused_imports)] use ::buffa::bytes::Buf as _; @@ -5805,7 +5805,7 @@ impl ::buffa::Message for EnumDescriptorProto { }); } let mut elem = ::core::default::Default::default(); - ::buffa::Message::merge_length_delimited(&mut elem, buf, depth)?; + ::buffa::Message::merge_length_delimited(&mut elem, buf, ctx)?; self.value.push(elem); } 3u32 => { @@ -5819,7 +5819,7 @@ impl ::buffa::Message for EnumDescriptorProto { ::buffa::Message::merge_length_delimited( self.options.get_or_insert_default(), buf, - depth, + ctx, )?; } 4u32 => { @@ -5831,7 +5831,7 @@ impl ::buffa::Message for EnumDescriptorProto { }); } let mut elem = ::core::default::Default::default(); - ::buffa::Message::merge_length_delimited(&mut elem, buf, depth)?; + ::buffa::Message::merge_length_delimited(&mut elem, buf, ctx)?; self.reserved_range.push(elem); } 5u32 => { @@ -5867,7 +5867,7 @@ impl ::buffa::Message for EnumDescriptorProto { } _ => { self.__buffa_unknown_fields - .push(::buffa::encoding::decode_unknown_field(tag, buf, depth)?); + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); } } ::core::result::Result::Ok(()) @@ -6134,7 +6134,7 @@ pub mod enum_descriptor_proto { &mut self, tag: ::buffa::encoding::Tag, buf: &mut impl ::buffa::bytes::Buf, - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result<(), ::buffa::DecodeError> { #[allow(unused_imports)] use ::buffa::bytes::Buf as _; @@ -6167,7 +6167,7 @@ pub mod enum_descriptor_proto { } _ => { self.__buffa_unknown_fields - .push(::buffa::encoding::decode_unknown_field(tag, buf, depth)?); + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); } } ::core::result::Result::Ok(()) @@ -6403,7 +6403,7 @@ impl ::buffa::Message for EnumValueDescriptorProto { &mut self, tag: ::buffa::encoding::Tag, buf: &mut impl ::buffa::bytes::Buf, - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result<(), ::buffa::DecodeError> { #[allow(unused_imports)] use ::buffa::bytes::Buf as _; @@ -6446,12 +6446,12 @@ impl ::buffa::Message for EnumValueDescriptorProto { ::buffa::Message::merge_length_delimited( self.options.get_or_insert_default(), buf, - depth, + ctx, )?; } _ => { self.__buffa_unknown_fields - .push(::buffa::encoding::decode_unknown_field(tag, buf, depth)?); + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); } } ::core::result::Result::Ok(()) @@ -6692,7 +6692,7 @@ impl ::buffa::Message for ServiceDescriptorProto { &mut self, tag: ::buffa::encoding::Tag, buf: &mut impl ::buffa::bytes::Buf, - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result<(), ::buffa::DecodeError> { #[allow(unused_imports)] use ::buffa::bytes::Buf as _; @@ -6721,7 +6721,7 @@ impl ::buffa::Message for ServiceDescriptorProto { }); } let mut elem = ::core::default::Default::default(); - ::buffa::Message::merge_length_delimited(&mut elem, buf, depth)?; + ::buffa::Message::merge_length_delimited(&mut elem, buf, ctx)?; self.method.push(elem); } 3u32 => { @@ -6735,12 +6735,12 @@ impl ::buffa::Message for ServiceDescriptorProto { ::buffa::Message::merge_length_delimited( self.options.get_or_insert_default(), buf, - depth, + ctx, )?; } _ => { self.__buffa_unknown_fields - .push(::buffa::encoding::decode_unknown_field(tag, buf, depth)?); + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); } } ::core::result::Result::Ok(()) @@ -7085,7 +7085,7 @@ impl ::buffa::Message for MethodDescriptorProto { &mut self, tag: ::buffa::encoding::Tag, buf: &mut impl ::buffa::bytes::Buf, - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result<(), ::buffa::DecodeError> { #[allow(unused_imports)] use ::buffa::bytes::Buf as _; @@ -7146,7 +7146,7 @@ impl ::buffa::Message for MethodDescriptorProto { ::buffa::Message::merge_length_delimited( self.options.get_or_insert_default(), buf, - depth, + ctx, )?; } 5u32 => { @@ -7175,7 +7175,7 @@ impl ::buffa::Message for MethodDescriptorProto { } _ => { self.__buffa_unknown_fields - .push(::buffa::encoding::decode_unknown_field(tag, buf, depth)?); + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); } } ::core::result::Result::Ok(()) @@ -8099,7 +8099,7 @@ impl ::buffa::Message for FileOptions { &mut self, tag: ::buffa::encoding::Tag, buf: &mut impl ::buffa::bytes::Buf, - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result<(), ::buffa::DecodeError> { #[allow(unused_imports)] use ::buffa::bytes::Buf as _; @@ -8384,7 +8384,7 @@ impl ::buffa::Message for FileOptions { ::buffa::Message::merge_length_delimited( self.features.get_or_insert_default(), buf, - depth, + ctx, )?; } 999u32 => { @@ -8396,12 +8396,12 @@ impl ::buffa::Message for FileOptions { }); } let mut elem = ::core::default::Default::default(); - ::buffa::Message::merge_length_delimited(&mut elem, buf, depth)?; + ::buffa::Message::merge_length_delimited(&mut elem, buf, ctx)?; self.uninterpreted_option.push(elem); } _ => { self.__buffa_unknown_fields - .push(::buffa::encoding::decode_unknown_field(tag, buf, depth)?); + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); } } ::core::result::Result::Ok(()) @@ -9573,7 +9573,7 @@ impl ::buffa::Message for MessageOptions { &mut self, tag: ::buffa::encoding::Tag, buf: &mut impl ::buffa::bytes::Buf, - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result<(), ::buffa::DecodeError> { #[allow(unused_imports)] use ::buffa::bytes::Buf as _; @@ -9651,7 +9651,7 @@ impl ::buffa::Message for MessageOptions { ::buffa::Message::merge_length_delimited( self.features.get_or_insert_default(), buf, - depth, + ctx, )?; } 999u32 => { @@ -9663,12 +9663,12 @@ impl ::buffa::Message for MessageOptions { }); } let mut elem = ::core::default::Default::default(); - ::buffa::Message::merge_length_delimited(&mut elem, buf, depth)?; + ::buffa::Message::merge_length_delimited(&mut elem, buf, ctx)?; self.uninterpreted_option.push(elem); } _ => { self.__buffa_unknown_fields - .push(::buffa::encoding::decode_unknown_field(tag, buf, depth)?); + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); } } ::core::result::Result::Ok(()) @@ -10510,7 +10510,7 @@ impl ::buffa::Message for FieldOptions { &mut self, tag: ::buffa::encoding::Tag, buf: &mut impl ::buffa::bytes::Buf, - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result<(), ::buffa::DecodeError> { #[allow(unused_imports)] use ::buffa::bytes::Buf as _; @@ -10712,7 +10712,7 @@ impl ::buffa::Message for FieldOptions { }); } let mut elem = ::core::default::Default::default(); - ::buffa::Message::merge_length_delimited(&mut elem, buf, depth)?; + ::buffa::Message::merge_length_delimited(&mut elem, buf, ctx)?; self.edition_defaults.push(elem); } 21u32 => { @@ -10726,7 +10726,7 @@ impl ::buffa::Message for FieldOptions { ::buffa::Message::merge_length_delimited( self.features.get_or_insert_default(), buf, - depth, + ctx, )?; } 22u32 => { @@ -10740,7 +10740,7 @@ impl ::buffa::Message for FieldOptions { ::buffa::Message::merge_length_delimited( self.feature_support.get_or_insert_default(), buf, - depth, + ctx, )?; } 999u32 => { @@ -10752,12 +10752,12 @@ impl ::buffa::Message for FieldOptions { }); } let mut elem = ::core::default::Default::default(); - ::buffa::Message::merge_length_delimited(&mut elem, buf, depth)?; + ::buffa::Message::merge_length_delimited(&mut elem, buf, ctx)?; self.uninterpreted_option.push(elem); } _ => { self.__buffa_unknown_fields - .push(::buffa::encoding::decode_unknown_field(tag, buf, depth)?); + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); } } ::core::result::Result::Ok(()) @@ -12130,7 +12130,7 @@ pub mod field_options { &mut self, tag: ::buffa::encoding::Tag, buf: &mut impl ::buffa::bytes::Buf, - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result<(), ::buffa::DecodeError> { #[allow(unused_imports)] use ::buffa::bytes::Buf as _; @@ -12175,7 +12175,7 @@ pub mod field_options { } _ => { self.__buffa_unknown_fields - .push(::buffa::encoding::decode_unknown_field(tag, buf, depth)?); + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); } } ::core::result::Result::Ok(()) @@ -12464,7 +12464,7 @@ pub mod field_options { &mut self, tag: ::buffa::encoding::Tag, buf: &mut impl ::buffa::bytes::Buf, - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result<(), ::buffa::DecodeError> { #[allow(unused_imports)] use ::buffa::bytes::Buf as _; @@ -12551,7 +12551,7 @@ pub mod field_options { } _ => { self.__buffa_unknown_fields - .push(::buffa::encoding::decode_unknown_field(tag, buf, depth)?); + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); } } ::core::result::Result::Ok(()) @@ -12800,7 +12800,7 @@ impl ::buffa::Message for OneofOptions { &mut self, tag: ::buffa::encoding::Tag, buf: &mut impl ::buffa::bytes::Buf, - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result<(), ::buffa::DecodeError> { #[allow(unused_imports)] use ::buffa::bytes::Buf as _; @@ -12818,7 +12818,7 @@ impl ::buffa::Message for OneofOptions { ::buffa::Message::merge_length_delimited( self.features.get_or_insert_default(), buf, - depth, + ctx, )?; } 999u32 => { @@ -12830,12 +12830,12 @@ impl ::buffa::Message for OneofOptions { }); } let mut elem = ::core::default::Default::default(); - ::buffa::Message::merge_length_delimited(&mut elem, buf, depth)?; + ::buffa::Message::merge_length_delimited(&mut elem, buf, ctx)?; self.uninterpreted_option.push(elem); } _ => { self.__buffa_unknown_fields - .push(::buffa::encoding::decode_unknown_field(tag, buf, depth)?); + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); } } ::core::result::Result::Ok(()) @@ -13299,7 +13299,7 @@ impl ::buffa::Message for EnumOptions { &mut self, tag: ::buffa::encoding::Tag, buf: &mut impl ::buffa::bytes::Buf, - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result<(), ::buffa::DecodeError> { #[allow(unused_imports)] use ::buffa::bytes::Buf as _; @@ -13353,7 +13353,7 @@ impl ::buffa::Message for EnumOptions { ::buffa::Message::merge_length_delimited( self.features.get_or_insert_default(), buf, - depth, + ctx, )?; } 999u32 => { @@ -13365,12 +13365,12 @@ impl ::buffa::Message for EnumOptions { }); } let mut elem = ::core::default::Default::default(); - ::buffa::Message::merge_length_delimited(&mut elem, buf, depth)?; + ::buffa::Message::merge_length_delimited(&mut elem, buf, ctx)?; self.uninterpreted_option.push(elem); } _ => { self.__buffa_unknown_fields - .push(::buffa::encoding::decode_unknown_field(tag, buf, depth)?); + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); } } ::core::result::Result::Ok(()) @@ -13890,7 +13890,7 @@ impl ::buffa::Message for EnumValueOptions { &mut self, tag: ::buffa::encoding::Tag, buf: &mut impl ::buffa::bytes::Buf, - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result<(), ::buffa::DecodeError> { #[allow(unused_imports)] use ::buffa::bytes::Buf as _; @@ -13920,7 +13920,7 @@ impl ::buffa::Message for EnumValueOptions { ::buffa::Message::merge_length_delimited( self.features.get_or_insert_default(), buf, - depth, + ctx, )?; } 3u32 => { @@ -13946,7 +13946,7 @@ impl ::buffa::Message for EnumValueOptions { ::buffa::Message::merge_length_delimited( self.feature_support.get_or_insert_default(), buf, - depth, + ctx, )?; } 999u32 => { @@ -13958,12 +13958,12 @@ impl ::buffa::Message for EnumValueOptions { }); } let mut elem = ::core::default::Default::default(); - ::buffa::Message::merge_length_delimited(&mut elem, buf, depth)?; + ::buffa::Message::merge_length_delimited(&mut elem, buf, ctx)?; self.uninterpreted_option.push(elem); } _ => { self.__buffa_unknown_fields - .push(::buffa::encoding::decode_unknown_field(tag, buf, depth)?); + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); } } ::core::result::Result::Ok(()) @@ -14427,7 +14427,7 @@ impl ::buffa::Message for ServiceOptions { &mut self, tag: ::buffa::encoding::Tag, buf: &mut impl ::buffa::bytes::Buf, - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result<(), ::buffa::DecodeError> { #[allow(unused_imports)] use ::buffa::bytes::Buf as _; @@ -14457,7 +14457,7 @@ impl ::buffa::Message for ServiceOptions { ::buffa::Message::merge_length_delimited( self.features.get_or_insert_default(), buf, - depth, + ctx, )?; } 999u32 => { @@ -14469,12 +14469,12 @@ impl ::buffa::Message for ServiceOptions { }); } let mut elem = ::core::default::Default::default(); - ::buffa::Message::merge_length_delimited(&mut elem, buf, depth)?; + ::buffa::Message::merge_length_delimited(&mut elem, buf, ctx)?; self.uninterpreted_option.push(elem); } _ => { self.__buffa_unknown_fields - .push(::buffa::encoding::decode_unknown_field(tag, buf, depth)?); + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); } } ::core::result::Result::Ok(()) @@ -14927,7 +14927,7 @@ impl ::buffa::Message for MethodOptions { &mut self, tag: ::buffa::encoding::Tag, buf: &mut impl ::buffa::bytes::Buf, - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result<(), ::buffa::DecodeError> { #[allow(unused_imports)] use ::buffa::bytes::Buf as _; @@ -14978,7 +14978,7 @@ impl ::buffa::Message for MethodOptions { ::buffa::Message::merge_length_delimited( self.features.get_or_insert_default(), buf, - depth, + ctx, )?; } 999u32 => { @@ -14990,12 +14990,12 @@ impl ::buffa::Message for MethodOptions { }); } let mut elem = ::core::default::Default::default(); - ::buffa::Message::merge_length_delimited(&mut elem, buf, depth)?; + ::buffa::Message::merge_length_delimited(&mut elem, buf, ctx)?; self.uninterpreted_option.push(elem); } _ => { self.__buffa_unknown_fields - .push(::buffa::encoding::decode_unknown_field(tag, buf, depth)?); + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); } } ::core::result::Result::Ok(()) @@ -15734,7 +15734,7 @@ impl ::buffa::Message for UninterpretedOption { &mut self, tag: ::buffa::encoding::Tag, buf: &mut impl ::buffa::bytes::Buf, - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result<(), ::buffa::DecodeError> { #[allow(unused_imports)] use ::buffa::bytes::Buf as _; @@ -15750,7 +15750,7 @@ impl ::buffa::Message for UninterpretedOption { }); } let mut elem = ::core::default::Default::default(); - ::buffa::Message::merge_length_delimited(&mut elem, buf, depth)?; + ::buffa::Message::merge_length_delimited(&mut elem, buf, ctx)?; self.name.push(elem); } 3u32 => { @@ -15834,7 +15834,7 @@ impl ::buffa::Message for UninterpretedOption { } _ => { self.__buffa_unknown_fields - .push(::buffa::encoding::decode_unknown_field(tag, buf, depth)?); + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); } } ::core::result::Result::Ok(()) @@ -16079,7 +16079,7 @@ pub mod uninterpreted_option { &mut self, tag: ::buffa::encoding::Tag, buf: &mut impl ::buffa::bytes::Buf, - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result<(), ::buffa::DecodeError> { #[allow(unused_imports)] use ::buffa::bytes::Buf as _; @@ -16108,7 +16108,7 @@ pub mod uninterpreted_option { } _ => { self.__buffa_unknown_fields - .push(::buffa::encoding::decode_unknown_field(tag, buf, depth)?); + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); } } ::core::result::Result::Ok(()) @@ -16508,7 +16508,7 @@ impl ::buffa::Message for FeatureSet { &mut self, tag: ::buffa::encoding::Tag, buf: &mut impl ::buffa::bytes::Buf, - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result<(), ::buffa::DecodeError> { #[allow(unused_imports)] use ::buffa::bytes::Buf as _; @@ -16685,7 +16685,7 @@ impl ::buffa::Message for FeatureSet { } _ => { self.__buffa_unknown_fields - .push(::buffa::encoding::decode_unknown_field(tag, buf, depth)?); + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); } } ::core::result::Result::Ok(()) @@ -18307,7 +18307,7 @@ pub mod feature_set { &mut self, tag: ::buffa::encoding::Tag, buf: &mut impl ::buffa::bytes::Buf, - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result<(), ::buffa::DecodeError> { #[allow(unused_imports)] use ::buffa::bytes::Buf as _; @@ -18316,7 +18316,7 @@ pub mod feature_set { match tag.field_number() { _ => { self.__buffa_unknown_fields - .push(::buffa::encoding::decode_unknown_field(tag, buf, depth)?); + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); } } ::core::result::Result::Ok(()) @@ -18751,7 +18751,7 @@ impl ::buffa::Message for FeatureSetDefaults { &mut self, tag: ::buffa::encoding::Tag, buf: &mut impl ::buffa::bytes::Buf, - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result<(), ::buffa::DecodeError> { #[allow(unused_imports)] use ::buffa::bytes::Buf as _; @@ -18767,7 +18767,7 @@ impl ::buffa::Message for FeatureSetDefaults { }); } let mut elem = ::core::default::Default::default(); - ::buffa::Message::merge_length_delimited(&mut elem, buf, depth)?; + ::buffa::Message::merge_length_delimited(&mut elem, buf, ctx)?; self.defaults.push(elem); } 4u32 => { @@ -18814,7 +18814,7 @@ impl ::buffa::Message for FeatureSetDefaults { } _ => { self.__buffa_unknown_fields - .push(::buffa::encoding::decode_unknown_field(tag, buf, depth)?); + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); } } ::core::result::Result::Ok(()) @@ -19077,7 +19077,7 @@ pub mod feature_set_defaults { &mut self, tag: ::buffa::encoding::Tag, buf: &mut impl ::buffa::bytes::Buf, - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result<(), ::buffa::DecodeError> { #[allow(unused_imports)] use ::buffa::bytes::Buf as _; @@ -19116,7 +19116,7 @@ pub mod feature_set_defaults { ::buffa::Message::merge_length_delimited( self.overridable_features.get_or_insert_default(), buf, - depth, + ctx, )?; } 5u32 => { @@ -19130,12 +19130,12 @@ pub mod feature_set_defaults { ::buffa::Message::merge_length_delimited( self.fixed_features.get_or_insert_default(), buf, - depth, + ctx, )?; } _ => { self.__buffa_unknown_fields - .push(::buffa::encoding::decode_unknown_field(tag, buf, depth)?); + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); } } ::core::result::Result::Ok(()) @@ -19380,7 +19380,7 @@ impl ::buffa::Message for SourceCodeInfo { &mut self, tag: ::buffa::encoding::Tag, buf: &mut impl ::buffa::bytes::Buf, - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result<(), ::buffa::DecodeError> { #[allow(unused_imports)] use ::buffa::bytes::Buf as _; @@ -19396,12 +19396,12 @@ impl ::buffa::Message for SourceCodeInfo { }); } let mut elem = ::core::default::Default::default(); - ::buffa::Message::merge_length_delimited(&mut elem, buf, depth)?; + ::buffa::Message::merge_length_delimited(&mut elem, buf, ctx)?; self.location.push(elem); } _ => { self.__buffa_unknown_fields - .push(::buffa::encoding::decode_unknown_field(tag, buf, depth)?); + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); } } ::core::result::Result::Ok(()) @@ -19942,7 +19942,7 @@ pub mod source_code_info { &mut self, tag: ::buffa::encoding::Tag, buf: &mut impl ::buffa::bytes::Buf, - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result<(), ::buffa::DecodeError> { #[allow(unused_imports)] use ::buffa::bytes::Buf as _; @@ -20050,7 +20050,7 @@ pub mod source_code_info { } _ => { self.__buffa_unknown_fields - .push(::buffa::encoding::decode_unknown_field(tag, buf, depth)?); + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); } } ::core::result::Result::Ok(()) @@ -20273,7 +20273,7 @@ impl ::buffa::Message for GeneratedCodeInfo { &mut self, tag: ::buffa::encoding::Tag, buf: &mut impl ::buffa::bytes::Buf, - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result<(), ::buffa::DecodeError> { #[allow(unused_imports)] use ::buffa::bytes::Buf as _; @@ -20289,12 +20289,12 @@ impl ::buffa::Message for GeneratedCodeInfo { }); } let mut elem = ::core::default::Default::default(); - ::buffa::Message::merge_length_delimited(&mut elem, buf, depth)?; + ::buffa::Message::merge_length_delimited(&mut elem, buf, ctx)?; self.annotation.push(elem); } _ => { self.__buffa_unknown_fields - .push(::buffa::encoding::decode_unknown_field(tag, buf, depth)?); + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); } } ::core::result::Result::Ok(()) @@ -20611,7 +20611,7 @@ pub mod generated_code_info { &mut self, tag: ::buffa::encoding::Tag, buf: &mut impl ::buffa::bytes::Buf, - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result<(), ::buffa::DecodeError> { #[allow(unused_imports)] use ::buffa::bytes::Buf as _; @@ -20709,7 +20709,7 @@ pub mod generated_code_info { } _ => { self.__buffa_unknown_fields - .push(::buffa::encoding::decode_unknown_field(tag, buf, depth)?); + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); } } ::core::result::Result::Ok(()) diff --git a/buffa-descriptor/src/reflect/dynamic.rs b/buffa-descriptor/src/reflect/dynamic.rs index d16b880e..65e2e0b4 100644 --- a/buffa-descriptor/src/reflect/dynamic.rs +++ b/buffa-descriptor/src/reflect/dynamic.rs @@ -34,7 +34,7 @@ use buffa::types::{ sint64_encoded_len, uint32_encoded_len, uint64_encoded_len, }; use buffa::unknown_fields::UnknownFields; -use buffa::{DecodeError, Message, RECURSION_LIMIT}; +use buffa::{DecodeContext, DecodeError, Message, DEFAULT_UNKNOWN_FIELD_LIMIT, RECURSION_LIMIT}; use super::message::{ReflectCow, ReflectMessage, ReflectMessageMut}; use super::value::{MapKey, MapValue, Value, ValueRef}; @@ -198,14 +198,15 @@ impl DynamicMessage { /// /// Returns a [`DecodeError`] if the wire data is malformed. pub fn merge(&mut self, bytes: &[u8]) -> Result<(), DecodeError> { + let limit = core::cell::Cell::new(DEFAULT_UNKNOWN_FIELD_LIMIT); let mut buf = bytes; - self.merge_buf(&mut buf, RECURSION_LIMIT) + self.merge_buf(&mut buf, DecodeContext::new(RECURSION_LIMIT, &limit)) } - fn merge_buf(&mut self, buf: &mut impl Buf, depth: u32) -> Result<(), DecodeError> { + fn merge_buf(&mut self, buf: &mut impl Buf, ctx: DecodeContext<'_>) -> Result<(), DecodeError> { while buf.has_remaining() { let tag = Tag::decode(buf)?; - self.merge_one_field(tag, buf, depth)?; + self.merge_one_field(tag, buf, ctx)?; } Ok(()) } @@ -215,7 +216,7 @@ impl DynamicMessage { &mut self, buf: &mut impl Buf, group_field_number: u32, - depth: u32, + ctx: DecodeContext<'_>, ) -> Result<(), DecodeError> { loop { let tag = Tag::decode(buf)?; @@ -225,7 +226,7 @@ impl DynamicMessage { } return Ok(()); } - self.merge_one_field(tag, buf, depth)?; + self.merge_one_field(tag, buf, ctx)?; } } @@ -233,7 +234,7 @@ impl DynamicMessage { &mut self, tag: Tag, buf: &mut impl Buf, - depth: u32, + ctx: DecodeContext<'_>, ) -> Result<(), DecodeError> { let number = tag.field_number(); // Take the FieldDescriptor by index to avoid borrowing the @@ -246,7 +247,7 @@ impl DynamicMessage { let (kind, oneof_index, delimited) = match self.field_or_extension(number) { Some(fd) => (fd.kind, fd.oneof_index, fd.delimited), None => { - self.unknown.push(decode_unknown_field(tag, buf, depth)?); + self.unknown.push(decode_unknown_field(tag, buf, ctx)?); return Ok(()); } }; @@ -259,7 +260,7 @@ impl DynamicMessage { // varint payload for a Fixed32 field) and silently corrupt every // subsequent field in the stream. if !wire_type_compatible(kind, tag.wire_type(), delimited) { - self.unknown.push(decode_unknown_field(tag, buf, depth)?); + self.unknown.push(decode_unknown_field(tag, buf, ctx)?); return Ok(()); } match kind { @@ -276,17 +277,17 @@ impl DynamicMessage { if let SingularKind::Message(midx) = sk { if let Some(Value::Message(_)) = self.fields.get(&number) { // Decode the new bytes into the existing message. - return self.merge_into_existing_message(number, midx, tag, buf, depth); + return self.merge_into_existing_message(number, midx, tag, buf, ctx); } } - let v = self.decode_element(sk, tag, buf, depth)?; + let v = self.decode_element(sk, tag, buf, ctx)?; self.fields.insert(number, v); } FieldKind::List(sk) => { - self.merge_list_field(number, sk, tag, buf, depth)?; + self.merge_list_field(number, sk, tag, buf, ctx)?; } FieldKind::Map { key, value } => { - self.merge_map_field(number, key, value, tag, buf, depth)?; + self.merge_map_field(number, key, value, tag, buf, ctx)?; } } Ok(()) @@ -319,12 +320,10 @@ impl DynamicMessage { midx: MessageIndex, tag: Tag, buf: &mut impl Buf, - depth: u32, + ctx: DecodeContext<'_>, ) -> Result<(), DecodeError> { let _ = midx; - let depth = depth - .checked_sub(1) - .ok_or(DecodeError::RecursionLimitExceeded)?; + let ctx = ctx.descend()?; // Take the existing message out of the map so we can borrow `self` // immutably for the descriptor lookup while merging into it. let Some(Value::Message(mut existing)) = self.fields.remove(&number) else { @@ -339,9 +338,9 @@ impl DynamicMessage { return Err(DecodeError::UnexpectedEof); } let mut sub = buf.copy_to_bytes(len); - existing.merge_buf(&mut sub, depth) + existing.merge_buf(&mut sub, ctx) } - WireType::StartGroup => existing.merge_group(buf, tag.field_number(), depth), + WireType::StartGroup => existing.merge_group(buf, tag.field_number(), ctx), wt => Err(DecodeError::WireTypeMismatch { field_number: number, expected: WireType::LengthDelimited as u8, @@ -360,7 +359,7 @@ impl DynamicMessage { elem: SingularKind, tag: Tag, buf: &mut impl Buf, - depth: u32, + ctx: DecodeContext<'_>, ) -> Result<(), DecodeError> { let list = match self .fields @@ -398,7 +397,7 @@ impl DynamicMessage { // we need first. // SAFETY: re-borrow `self.fields` after the descriptor look-up. Since // we already extracted `elem` as a Copy, no aliasing occurs. - let v = self.decode_element_no_alias(elem, tag, buf, depth)?; + let v = self.decode_element_no_alias(elem, tag, buf, ctx)?; // Re-fetch the list — `decode_element_no_alias` may have allocated // entries in `self.fields` if `elem` is a message... it didn't, but // the borrow checker doesn't know that. Re-fetch is cheap. @@ -417,13 +416,13 @@ impl DynamicMessage { value_kind: SingularKind, tag: Tag, buf: &mut impl Buf, - depth: u32, + ctx: DecodeContext<'_>, ) -> Result<(), DecodeError> { // A map entry is a length-delimited message with fields 1 (key) and // 2 (value). if tag.wire_type() != WireType::LengthDelimited { // Unexpected wire type — skip and preserve as unknown. - self.unknown.push(decode_unknown_field(tag, buf, depth)?); + self.unknown.push(decode_unknown_field(tag, buf, ctx)?); return Ok(()); } let len = decode_varint(buf)?; @@ -439,14 +438,19 @@ impl DynamicMessage { match entry_tag.field_number() { 1 => key = Some(decode_map_key(key_ty, entry_tag, &mut entry)?), 2 => { + // The map entry is a sub-message on the wire, so it + // consumes one depth level. (The previous code used + // `depth.saturating_sub(1)` here, which let scalar map + // values through at exactly depth 0; erroring one level + // earlier is intentional.) value = Some(self.decode_element_no_alias( value_kind, entry_tag, &mut entry, - depth.saturating_sub(1), + ctx.descend()?, )?); } - _ => skip_field_depth(entry_tag, &mut entry, depth)?, + _ => skip_field_depth(entry_tag, &mut entry, ctx.depth())?, } } let k = key.unwrap_or_else(|| default_map_key(key_ty)); @@ -475,9 +479,9 @@ impl DynamicMessage { kind: SingularKind, tag: Tag, buf: &mut impl Buf, - depth: u32, + ctx: DecodeContext<'_>, ) -> Result { - self.decode_element_no_alias(kind, tag, buf, depth) + self.decode_element_no_alias(kind, tag, buf, ctx) } /// Decode one singular element. Named to distinguish call sites where @@ -487,7 +491,7 @@ impl DynamicMessage { kind: SingularKind, tag: Tag, buf: &mut impl Buf, - depth: u32, + ctx: DecodeContext<'_>, ) -> Result { match kind { SingularKind::Scalar(s) => decode_scalar(s, tag.wire_type(), buf), @@ -497,9 +501,7 @@ impl DynamicMessage { } SingularKind::Message(midx) => { let mut nested = DynamicMessage::new(Arc::clone(&self.pool), midx); - let depth = depth - .checked_sub(1) - .ok_or(DecodeError::RecursionLimitExceeded)?; + let ctx = ctx.descend()?; match tag.wire_type() { WireType::LengthDelimited => { let len = decode_varint(buf)?; @@ -508,10 +510,10 @@ impl DynamicMessage { return Err(DecodeError::UnexpectedEof); } let mut sub = buf.copy_to_bytes(len); - nested.merge_buf(&mut sub, depth)?; + nested.merge_buf(&mut sub, ctx)?; } WireType::StartGroup => { - nested.merge_group(buf, tag.field_number(), depth)?; + nested.merge_group(buf, tag.field_number(), ctx)?; } _ => { return Err(DecodeError::WireTypeMismatch { diff --git a/buffa-test/src/tests/basic.rs b/buffa-test/src/tests/basic.rs index 7ff9a176..abacfdf7 100644 --- a/buffa-test/src/tests/basic.rs +++ b/buffa-test/src/tests/basic.rs @@ -189,8 +189,12 @@ fn test_merge_appends_repeated_fields() { b.tags = vec!["y".into(), "z".into()]; b.encode_to_vec() }; - a.merge(&mut b_bytes.as_slice(), buffa::RECURSION_LIMIT) - .unwrap(); + let limit = core::cell::Cell::new(buffa::DEFAULT_UNKNOWN_FIELD_LIMIT); + a.merge( + &mut b_bytes.as_slice(), + buffa::DecodeContext::new(buffa::RECURSION_LIMIT, &limit), + ) + .unwrap(); assert_eq!(a.tags, vec!["x", "y", "z"]); } diff --git a/buffa-test/src/tests/bytes_type.rs b/buffa-test/src/tests/bytes_type.rs index 98e26b0d..49ea0cf5 100644 --- a/buffa-test/src/tests/bytes_type.rs +++ b/buffa-test/src/tests/bytes_type.rs @@ -60,7 +60,7 @@ fn test_bytes_type_view_to_owned() { let view = PersonView::decode_view(&wire).expect("decode_view"); assert_eq!(view.avatar, &[0xCA, 0xFE][..]); // to_owned_message produces Bytes. - let owned: Person = view.to_owned_message(); + let owned: Person = view.to_owned_message().unwrap(); assert_eq!(&owned.avatar[..], &[0xCA, 0xFE]); assert_eq!(owned.encode_to_vec(), wire); } @@ -105,7 +105,7 @@ fn test_bytes_type_repeated_view_to_owned() { // to_owned_message: Vec<&[u8]> → Vec. // Generated: self.many.iter().map(|b| bytes_from_source(__buffa_src, b)).collect() // where b: &&[u8]; the &[u8] arg auto-derefs. - let owned: BytesContexts = view.to_owned_message(); + let owned: BytesContexts = view.to_owned_message().unwrap(); assert_eq!(owned.many.len(), 3); assert_eq!(&owned.many[0][..], b"a"); assert_eq!(&owned.many[1][..], b"bc"); @@ -129,7 +129,7 @@ fn test_bytes_type_oneof_view_to_owned() { // Generated: self.choice.as_ref().map(|v| match v { // ChoiceView::Raw(v) => Choice::Raw(bytes_from_source(__buffa_src, v)), ... }) // Match ergonomics: v in the arm is &&[u8]; the &[u8] arg auto-derefs. - let owned: BytesContexts = view.to_owned_message(); + let owned: BytesContexts = view.to_owned_message().unwrap(); match &owned.choice { Some(ChoiceOneof::Raw(b)) => assert_eq!(&b[..], &[0x00, 0xFF, 0x7F]), other => panic!("expected Choice::Raw, got {other:?}"), @@ -153,7 +153,7 @@ fn test_bytes_type_optional_view_to_owned() { }; let wire = msg.encode_to_vec(); let view = BytesContextsView::decode_view(&wire).expect("decode_view"); - let owned: BytesContexts = view.to_owned_message(); + let owned: BytesContexts = view.to_owned_message().unwrap(); assert_eq!( owned.maybe.as_deref(), input, @@ -180,7 +180,7 @@ fn test_bytes_type_view_to_owned_from_source_zero_copy() { }; let view = BytesContextsView::decode_view(&buf).expect("decode_view"); - let owned = view.to_owned_from_source(Some(&buf)); + let owned = view.to_owned_from_source(Some(&buf)).unwrap(); assert_eq!(&owned.many[0][..], b"aaaa"); assert!( @@ -265,7 +265,7 @@ fn test_bytes_type_nested_to_owned_from_source_zero_copy() { }; let buf = bytes::Bytes::from(msg.encode_to_vec()); let view = BytesNestedView::decode_view(&buf).expect("decode_view"); - let owned = view.to_owned_from_source(Some(&buf)); + let owned = view.to_owned_from_source(Some(&buf)).unwrap(); let inner_bytes = &owned.inner.singular; assert_eq!(&inner_bytes[..], b"nested-payload"); let r = buf.as_ptr() as usize..buf.as_ptr() as usize + buf.len(); @@ -383,7 +383,7 @@ fn test_bytes_type_map_value_uses_bytes() { let wire = msg.encode_to_vec(); let view = BytesContextsView::decode_view(&wire).expect("decode_view"); - let owned: BytesContexts = view.to_owned_message(); + let owned: BytesContexts = view.to_owned_message().unwrap(); assert_eq!(owned.by_key.get("k").map(|b| &b[..]), Some(&b"v"[..])); // Owned binary decode (impl_message::map_merge_arm's decode_bytes_to_bytes @@ -413,7 +413,7 @@ fn test_bytes_type_map_value_to_owned_from_source_zero_copy() { }; let view = BytesContextsView::decode_view(&buf).expect("decode_view"); - let owned = view.to_owned_from_source(Some(&buf)); + let owned = view.to_owned_from_source(Some(&buf)).unwrap(); let value = owned.by_key.get("k").expect("map value"); assert_eq!(&value[..], b"map-val"); diff --git a/buffa-test/src/tests/closed_enum.rs b/buffa-test/src/tests/closed_enum.rs index a4fcbc1a..6423392c 100644 --- a/buffa-test/src/tests/closed_enum.rs +++ b/buffa-test/src/tests/closed_enum.rs @@ -189,7 +189,7 @@ fn test_view_closed_enum_optional_unknown_to_unknown_fields() { assert_eq!(view.opt, None, "field must stay unset"); assert!(!view.__buffa_unknown_fields.is_empty()); // View → owned → encode must match original. - let owned = view.to_owned_message(); + let owned = view.to_owned_message().unwrap(); assert_eq!(owned.encode_to_vec(), wire); } @@ -210,7 +210,7 @@ fn test_view_closed_enum_repeated_unpacked_unknown_preserved() { // Unknown value span in unknown_fields. assert!(!view.__buffa_unknown_fields.is_empty()); // View → owned → decode again: same state. - let owned = view.to_owned_message(); + let owned = view.to_owned_message().unwrap(); let re = owned.encode_to_vec(); let view2 = ClosedEnumContextsView::decode_view(&re).unwrap(); let vals2: Vec<_> = view2.rep.iter().copied().collect(); @@ -226,7 +226,7 @@ fn test_view_closed_enum_oneof_unknown_to_unknown_fields() { let view = ClosedEnumContextsView::decode_view(&wire).unwrap(); assert!(view.choice.is_none(), "oneof must stay unset"); assert!(!view.__buffa_unknown_fields.is_empty()); - let owned = view.to_owned_message(); + let owned = view.to_owned_message().unwrap(); assert_eq!(owned.encode_to_vec(), wire); } @@ -256,7 +256,8 @@ fn test_view_owned_parity_for_closed_enum_unknowns() { let owned_direct = ClosedEnumContexts::decode(&mut wire.as_slice()).unwrap(); let via_view = ClosedEnumContextsView::decode_view(&wire) .unwrap() - .to_owned_message(); + .to_owned_message() + .unwrap(); assert_eq!( owned_direct.encode_to_vec(), via_view.encode_to_vec(), diff --git a/buffa-test/src/tests/nesting.rs b/buffa-test/src/tests/nesting.rs index 2239d61c..90d9a185 100644 --- a/buffa-test/src/tests/nesting.rs +++ b/buffa-test/src/tests/nesting.rs @@ -281,7 +281,7 @@ fn test_view_oneof_boxed_message_variant() { other => panic!("expected Negated, got {other:?}"), } // to_owned_message round-trips through both Box levels. - let owned = view.to_owned_message(); + let owned = view.to_owned_message().unwrap(); assert_eq!(owned, outer); } @@ -306,7 +306,7 @@ fn test_view_oneof_message_variant_to_owned() { Some(nested::__buffa::view::oneof::outer::Content::Structured(m)) => assert_eq!(m.value, 7), other => panic!("expected Structured, got {other:?}"), } - assert_eq!(view.to_owned_message(), msg); + assert_eq!(view.to_owned_message().unwrap(), msg); } #[test] @@ -360,7 +360,7 @@ fn test_view_recursive_singular_message_field() { assert_eq!(view.nested.value, 42); assert_eq!(view.nested.back.name, "leaf"); // Round-trip through to_owned_message. - assert_eq!(view.to_owned_message(), msg); + assert_eq!(view.to_owned_message().unwrap(), msg); } #[test] @@ -403,7 +403,7 @@ fn test_view_message_field_merge_semantics() { // Parity: view and owned decode must produce identical output. let owned = Corecursive::decode(&mut wire.as_slice()).unwrap(); assert_eq!( - view.to_owned_message().encode_to_vec(), + view.to_owned_message().unwrap().encode_to_vec(), owned.encode_to_vec() ); } @@ -454,7 +454,7 @@ fn test_view_oneof_message_variant_merge_semantics() { // Parity with owned decoder. let owned = Expr::decode(&mut wire.as_slice()).unwrap(); assert_eq!( - view.to_owned_message().encode_to_vec(), + view.to_owned_message().unwrap().encode_to_vec(), owned.encode_to_vec() ); } diff --git a/buffa-test/src/tests/owned_view.rs b/buffa-test/src/tests/owned_view.rs index 459fc900..c6b275f3 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(); + let back: Person = owned.to_owned_message().unwrap(); 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(), len) + (raw.to_owned_message().unwrap(), len) } #[test] diff --git a/buffa-test/src/tests/proto2.rs b/buffa-test/src/tests/proto2.rs index 2f92e653..b9720f35 100644 --- a/buffa-test/src/tests/proto2.rs +++ b/buffa-test/src/tests/proto2.rs @@ -342,7 +342,7 @@ fn test_view_coverage_via_view() { assert_eq!((*k, *v), ("med", Priority::MEDIUM)); // to_owned_message parity. - let owned = view.to_owned_message(); + let owned = view.to_owned_message().unwrap(); assert_eq!(owned.level, Priority::HIGH); assert_eq!(owned.by_id.get(&7).map(String::as_str), Some("seven")); assert_eq!(owned.priorities.get("med"), Some(&Priority::MEDIUM)); @@ -407,7 +407,7 @@ fn test_view_coverage_group_in_oneof_merge() { wire.extend_from_slice(&second.encode_to_vec()); let view = ViewCoverageView::decode_view(&wire).unwrap(); - let owned = view.to_owned_message(); + let owned = view.to_owned_message().unwrap(); match owned.choice { Some(ChoiceOneof::Payload(p)) => { // Both x (from first) and y (from second) should be present. diff --git a/buffa-test/src/tests/proto3_semantics.rs b/buffa-test/src/tests/proto3_semantics.rs index 8ca0a61b..e8ede073 100644 --- a/buffa-test/src/tests/proto3_semantics.rs +++ b/buffa-test/src/tests/proto3_semantics.rs @@ -578,7 +578,7 @@ fn view_implicit_presence_matches_owned() { assert_eq!(view.i64, 0); assert!(!view.b); - let owned = view.to_owned_message(); + let owned = view.to_owned_message().unwrap(); assert_eq!(owned, msg); } @@ -597,7 +597,7 @@ fn view_optional_some_zero_matches_owned() { assert_eq!(view.b, Some(false)); // View → owned → encode must match original bytes. - assert_eq!(view.to_owned_message().encode_to_vec(), bytes); + assert_eq!(view.to_owned_message().unwrap().encode_to_vec(), bytes); } #[test] @@ -616,5 +616,5 @@ fn view_open_enum_unknown_preserved() { vec![EnumValue::Known(Color::RED), EnumValue::Unknown(99)] ); - assert_eq!(view.to_owned_message(), msg); + assert_eq!(view.to_owned_message().unwrap(), msg); } diff --git a/buffa-test/src/tests/string_type.rs b/buffa-test/src/tests/string_type.rs index bec8f204..99f858bf 100644 --- a/buffa-test/src/tests/string_type.rs +++ b/buffa-test/src/tests/string_type.rs @@ -95,7 +95,7 @@ fn test_string_type_view_to_owned() { // Views always borrow &str regardless of the owned representation. assert_eq!(view.singular, "hello"); assert_eq!(view.compact, "compact-value"); - let owned: StringContexts = view.to_owned_message(); + let owned: StringContexts = view.to_owned_message().unwrap(); assert_eq!(owned, msg); // to_owned built the configured types, not String. let _: ::buffa::smol_str::SmolStr = owned.singular.clone(); diff --git a/buffa-test/src/tests/unbox_oneof.rs b/buffa-test/src/tests/unbox_oneof.rs index 938f2c6b..de78ee39 100644 --- a/buffa-test/src/tests/unbox_oneof.rs +++ b/buffa-test/src/tests/unbox_oneof.rs @@ -103,7 +103,7 @@ fn inline_variant_view_to_owned_roundtrip() { // (oneof_variant_to_owned in view.rs branches on variant_boxed). let bytes = envelope_small(13).encode_to_vec(); let view = crate::unbox_oneof::EnvelopeView::decode_view(&bytes).expect("decode_view"); - let owned = view.to_owned_message(); + let owned = view.to_owned_message().unwrap(); match owned.body { Some(Body::Small(s)) => assert_eq!(s.value, 13), other => panic!("expected Body::Small, got {other:?}"), diff --git a/buffa-test/src/tests/view.rs b/buffa-test/src/tests/view.rs index 4ef1ecaa..50e2f8e7 100644 --- a/buffa-test/src/tests/view.rs +++ b/buffa-test/src/tests/view.rs @@ -8,6 +8,15 @@ use crate::basic::*; use buffa::view::OwnedView; use buffa::{Message, MessageView, ViewEncode}; +/// Build a `DecodeContext` at `depth` with a fresh default unknown-field +/// allowance, leaking the cell (tests only). +fn view_ctx(depth: u32) -> buffa::DecodeContext<'static> { + let limit = Box::leak(Box::new(core::cell::Cell::new( + buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ))); + buffa::DecodeContext::new(depth, limit) +} + #[test] fn test_view_decodes_scalar_fields() { let mut msg = Person::default(); @@ -121,7 +130,7 @@ fn test_view_to_owned_roundtrip() { msg.contact = Some(oneof::person::Contact::Phone("+1-555-0000".into())); let bytes = msg.encode_to_vec(); let view = PersonView::decode_view(&bytes).expect("decode_view"); - let owned = view.to_owned_message(); + let owned = view.to_owned_message().unwrap(); assert_eq!(owned.id, 42); assert_eq!(owned.name, "Carol"); assert_eq!(owned.tags, vec!["x", "y"]); @@ -161,7 +170,7 @@ fn test_view_recursion_limit_exceeded() { let mut msg = Person::default(); msg.address.get_or_insert_default().street = "1 Main St".into(); let bytes = msg.encode_to_vec(); - let result = PersonView::_decode_depth(&bytes, 0); + let result = PersonView::_decode_ctx(&bytes, view_ctx(0)); assert!( matches!(result, Err(buffa::DecodeError::RecursionLimitExceeded)), "expected RecursionLimitExceeded, got {result:?}" @@ -187,14 +196,14 @@ fn test_unknown_group_respects_depth_budget() { // Via Person merge (owned path, preserve_unknown_fields=true by default // — decode_unknown_field is used there, which was already correct). // The view path is what was broken. - let result = PersonView::_decode_depth(&wire, 1); + let result = PersonView::_decode_ctx(&wire, view_ctx(1)); assert!( matches!(result, Err(buffa::DecodeError::RecursionLimitExceeded)), "unknown nested group must respect depth budget, got {result:?}" ); // With depth=2, should succeed (one level per group). - let result = PersonView::_decode_depth(&wire, 2); + let result = PersonView::_decode_ctx(&wire, view_ctx(2)); assert!(result.is_ok(), "depth=2 should suffice, got {result:?}"); } @@ -233,7 +242,7 @@ fn test_view_map_to_owned_roundtrip() { inv.stock.insert("y".into(), 7); let bytes = inv.encode_to_vec(); let view = InventoryView::decode_view(&bytes).expect("decode_view"); - let owned = view.to_owned_message(); + let owned = view.to_owned_message().unwrap(); assert_eq!(owned.stock.get("x"), Some(&42)); assert_eq!(owned.stock.get("y"), Some(&7)); } @@ -247,7 +256,7 @@ fn test_view_map_message_to_owned_roundtrip() { inv.locations.insert("hq".into(), addr.clone()); let bytes = inv.encode_to_vec(); let view = InventoryView::decode_view(&bytes).expect("decode_view"); - let owned = view.to_owned_message(); + let owned = view.to_owned_message().unwrap(); assert_eq!(owned.locations.get("hq"), Some(&addr)); } @@ -330,7 +339,7 @@ fn test_view_map_with_open_enum_value() { // Unknown value survives view decode + to_owned. assert_eq!(collected.get("svc3"), Some(&buffa::EnumValue::Unknown(99))); - let owned = view.to_owned_message(); + let owned = view.to_owned_message().unwrap(); assert_eq!( owned.statuses.get("svc1"), Some(&buffa::EnumValue::Known(Status::ACTIVE)) @@ -356,7 +365,7 @@ fn test_view_no_unknown_fields_all_scalar_compiles() { let e = Empty::default(); let bytes = e.encode_to_vec(); let view = EmptyView::decode_view(&bytes).unwrap(); - let _owned = view.to_owned_message(); + let _owned = view.to_owned_message().unwrap(); let mut s = AllScalars::default(); s.f_int32 = 42; @@ -365,7 +374,7 @@ fn test_view_no_unknown_fields_all_scalar_compiles() { let view = AllScalarsView::decode_view(&bytes).unwrap(); assert_eq!(view.f_int32, 42); assert!(view.f_bool); - let owned = view.to_owned_message(); + let owned = view.to_owned_message().unwrap(); assert_eq!(owned.f_int32, 42); } diff --git a/buffa-test/src/tests/wkt.rs b/buffa-test/src/tests/wkt.rs index cb39fdc6..4935aa9a 100644 --- a/buffa-test/src/tests/wkt.rs +++ b/buffa-test/src/tests/wkt.rs @@ -103,5 +103,5 @@ fn test_wkt_view_with_extern_path() { assert_eq!(view.created_at.seconds, 42); assert_eq!(view.created_at.nanos, 999); // Full round-trip. - assert_eq!(view.to_owned_message().encode_to_vec(), wire); + assert_eq!(view.to_owned_message().unwrap().encode_to_vec(), wire); } diff --git a/buffa-types/src/any_ext.rs b/buffa-types/src/any_ext.rs index ee5b98c0..724959f6 100644 --- a/buffa-types/src/any_ext.rs +++ b/buffa-types/src/any_ext.rs @@ -363,7 +363,7 @@ mod tests { // Direct trait path: to_owned_from_source(Some(&buf)) → slice_ref. let view = AnyView::decode_view(&buf).unwrap(); - let owned = view.to_owned_from_source(Some(&buf)); + let owned = view.to_owned_from_source(Some(&buf)).unwrap(); assert_eq!(owned.value, src.value); let value_ptr = owned.value.as_ptr() as usize; let buf_range = (buf.as_ptr() as usize)..(buf.as_ptr() as usize + buf.len()); @@ -376,12 +376,12 @@ 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(); + let owned2 = ov.to_owned_message().unwrap(); assert_eq!(owned2.value, src.value); assert!(buf_range.contains(&(owned2.value.as_ptr() as usize))); // No-source path still copies (correct, distinct allocation). - let copied = view.to_owned_message(); + let copied = view.to_owned_message().unwrap(); assert_eq!(copied.value, src.value); assert!(!buf_range.contains(&(copied.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 979ed9b8..dcf84442 100644 --- a/buffa-types/src/generated/google.protobuf.any.__view.rs +++ b/buffa-types/src/generated/google.protobuf.any.__view.rs @@ -138,20 +138,22 @@ pub struct AnyView<'a> { pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, } impl<'a> AnyView<'a> { - /// Decode from `buf`, enforcing a recursion depth limit for nested messages. + /// Decode from `buf` under the limits carried by `ctx` (recursion + /// depth and the shared unknown-field allowance). /// - /// Called by [`::buffa::MessageView::decode_view`] with [`::buffa::RECURSION_LIMIT`] - /// and by generated sub-message decode arms with `depth - 1`. + /// Called by [`::buffa::MessageView::decode_view`] with a fresh + /// default context and by generated sub-message decode arms with + /// `ctx.descend()?`. /// /// **Not part of the public API.** Named with a leading underscore to /// signal that it is for generated-code use only. #[doc(hidden)] - pub fn _decode_depth( + pub fn _decode_ctx( buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result { let mut view = Self::default(); - view._merge_into_view(buf, depth)?; + view._merge_into_view(buf, ctx)?; ::core::result::Result::Ok(view) } /// Merge fields from `buf` into this view (proto merge semantics). @@ -165,9 +167,9 @@ impl<'a> AnyView<'a> { pub fn _merge_into_view( &mut self, buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result<(), ::buffa::DecodeError> { - let _ = depth; + let _ = ctx; #[allow(unused_variables)] let view = self; let mut cur: &'a [u8] = buf; @@ -196,9 +198,9 @@ impl<'a> AnyView<'a> { view.value = ::buffa::types::borrow_bytes(&mut cur)?; } _ => { - ::buffa::encoding::skip_field_depth(tag, &mut cur, depth)?; + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; let span_len = before_tag.len() - cur.len(); - view.__buffa_unknown_fields.push_raw(&before_tag[..span_len]); + view.__buffa_unknown_fields.push_record(before_tag, span_len, ctx)?; } } } @@ -208,35 +210,37 @@ impl<'a> AnyView<'a> { impl<'a> ::buffa::MessageView<'a> for AnyView<'a> { type Owned = super::super::Any; fn decode_view(buf: &'a [u8]) -> ::core::result::Result { - Self::_decode_depth(buf, ::buffa::RECURSION_LIMIT) + let __limit = ::core::cell::Cell::new(::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT); + Self::_decode_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit), + ) } - fn decode_view_with_limit( + fn decode_view_with_ctx( buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result { - Self::_decode_depth(buf, depth) + Self::_decode_ctx(buf, ctx) } - fn to_owned_message(&self) -> super::super::Any { + fn to_owned_message( + &self, + ) -> ::core::result::Result { self.to_owned_from_source(None) } #[allow(clippy::useless_conversion, clippy::needless_update)] fn to_owned_from_source( &self, __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, - ) -> super::super::Any { + ) -> ::core::result::Result { #[allow(unused_imports)] use ::buffa::alloc::string::ToString as _; let _ = __buffa_src; - super::super::Any { + ::core::result::Result::Ok(super::super::Any { type_url: self.type_url.to_string(), value: ::buffa::view::bytes_from_source(__buffa_src, self.value), - __buffa_unknown_fields: self - .__buffa_unknown_fields - .to_owned() - .unwrap_or_default() - .into(), + __buffa_unknown_fields: self.__buffa_unknown_fields.to_owned()?.into(), ..::core::default::Default::default() - } + }) } } impl<'a> ::buffa::ViewEncode<'a> for AnyView<'a> { @@ -359,8 +363,14 @@ impl AnyOwnedView { self.0.reborrow() } /// Convert to the owned message type. - #[must_use] - pub fn to_owned_message(&self) -> super::super::Any { + /// + /// # 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 { self.0.to_owned_message() } /// The underlying bytes buffer. diff --git a/buffa-types/src/generated/google.protobuf.any.rs b/buffa-types/src/generated/google.protobuf.any.rs index 0ca6249a..a6987387 100644 --- a/buffa-types/src/generated/google.protobuf.any.rs +++ b/buffa-types/src/generated/google.protobuf.any.rs @@ -318,7 +318,7 @@ impl ::buffa::Message for Any { &mut self, tag: ::buffa::encoding::Tag, buf: &mut impl ::buffa::bytes::Buf, - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result<(), ::buffa::DecodeError> { #[allow(unused_imports)] use ::buffa::bytes::Buf as _; @@ -347,7 +347,7 @@ impl ::buffa::Message for Any { } _ => { self.__buffa_unknown_fields - .push(::buffa::encoding::decode_unknown_field(tag, buf, depth)?); + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); } } ::core::result::Result::Ok(()) diff --git a/buffa-types/src/generated/google.protobuf.duration.__view.rs b/buffa-types/src/generated/google.protobuf.duration.__view.rs index 699a1971..41316af6 100644 --- a/buffa-types/src/generated/google.protobuf.duration.__view.rs +++ b/buffa-types/src/generated/google.protobuf.duration.__view.rs @@ -85,20 +85,22 @@ pub struct DurationView<'a> { pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, } impl<'a> DurationView<'a> { - /// Decode from `buf`, enforcing a recursion depth limit for nested messages. + /// Decode from `buf` under the limits carried by `ctx` (recursion + /// depth and the shared unknown-field allowance). /// - /// Called by [`::buffa::MessageView::decode_view`] with [`::buffa::RECURSION_LIMIT`] - /// and by generated sub-message decode arms with `depth - 1`. + /// Called by [`::buffa::MessageView::decode_view`] with a fresh + /// default context and by generated sub-message decode arms with + /// `ctx.descend()?`. /// /// **Not part of the public API.** Named with a leading underscore to /// signal that it is for generated-code use only. #[doc(hidden)] - pub fn _decode_depth( + pub fn _decode_ctx( buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result { let mut view = Self::default(); - view._merge_into_view(buf, depth)?; + view._merge_into_view(buf, ctx)?; ::core::result::Result::Ok(view) } /// Merge fields from `buf` into this view (proto merge semantics). @@ -112,9 +114,9 @@ impl<'a> DurationView<'a> { pub fn _merge_into_view( &mut self, buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result<(), ::buffa::DecodeError> { - let _ = depth; + let _ = ctx; #[allow(unused_variables)] let view = self; let mut cur: &'a [u8] = buf; @@ -143,9 +145,9 @@ impl<'a> DurationView<'a> { view.nanos = ::buffa::types::decode_int32(&mut cur)?; } _ => { - ::buffa::encoding::skip_field_depth(tag, &mut cur, depth)?; + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; let span_len = before_tag.len() - cur.len(); - view.__buffa_unknown_fields.push_raw(&before_tag[..span_len]); + view.__buffa_unknown_fields.push_record(before_tag, span_len, ctx)?; } } } @@ -155,35 +157,37 @@ impl<'a> DurationView<'a> { impl<'a> ::buffa::MessageView<'a> for DurationView<'a> { type Owned = super::super::Duration; fn decode_view(buf: &'a [u8]) -> ::core::result::Result { - Self::_decode_depth(buf, ::buffa::RECURSION_LIMIT) + let __limit = ::core::cell::Cell::new(::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT); + Self::_decode_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit), + ) } - fn decode_view_with_limit( + fn decode_view_with_ctx( buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result { - Self::_decode_depth(buf, depth) + Self::_decode_ctx(buf, ctx) } - fn to_owned_message(&self) -> super::super::Duration { + fn to_owned_message( + &self, + ) -> ::core::result::Result { self.to_owned_from_source(None) } #[allow(clippy::useless_conversion, clippy::needless_update)] fn to_owned_from_source( &self, __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, - ) -> super::super::Duration { + ) -> ::core::result::Result { #[allow(unused_imports)] use ::buffa::alloc::string::ToString as _; let _ = __buffa_src; - super::super::Duration { + ::core::result::Result::Ok(super::super::Duration { seconds: self.seconds, nanos: self.nanos, - __buffa_unknown_fields: self - .__buffa_unknown_fields - .to_owned() - .unwrap_or_default() - .into(), + __buffa_unknown_fields: self.__buffa_unknown_fields.to_owned()?.into(), ..::core::default::Default::default() - } + }) } } impl<'a> ::buffa::ViewEncode<'a> for DurationView<'a> { @@ -302,8 +306,14 @@ impl DurationOwnedView { self.0.reborrow() } /// Convert to the owned message type. - #[must_use] - pub fn to_owned_message(&self) -> super::super::Duration { + /// + /// # 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 { self.0.to_owned_message() } /// The underlying bytes buffer. diff --git a/buffa-types/src/generated/google.protobuf.duration.rs b/buffa-types/src/generated/google.protobuf.duration.rs index dd977daa..bf375413 100644 --- a/buffa-types/src/generated/google.protobuf.duration.rs +++ b/buffa-types/src/generated/google.protobuf.duration.rs @@ -255,7 +255,7 @@ impl ::buffa::Message for Duration { &mut self, tag: ::buffa::encoding::Tag, buf: &mut impl ::buffa::bytes::Buf, - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result<(), ::buffa::DecodeError> { #[allow(unused_imports)] use ::buffa::bytes::Buf as _; @@ -284,7 +284,7 @@ impl ::buffa::Message for Duration { } _ => { self.__buffa_unknown_fields - .push(::buffa::encoding::decode_unknown_field(tag, buf, depth)?); + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); } } ::core::result::Result::Ok(()) diff --git a/buffa-types/src/generated/google.protobuf.empty.__view.rs b/buffa-types/src/generated/google.protobuf.empty.__view.rs index 12eb4b30..d8b2289e 100644 --- a/buffa-types/src/generated/google.protobuf.empty.__view.rs +++ b/buffa-types/src/generated/google.protobuf.empty.__view.rs @@ -15,20 +15,22 @@ pub struct EmptyView<'a> { pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, } impl<'a> EmptyView<'a> { - /// Decode from `buf`, enforcing a recursion depth limit for nested messages. + /// Decode from `buf` under the limits carried by `ctx` (recursion + /// depth and the shared unknown-field allowance). /// - /// Called by [`::buffa::MessageView::decode_view`] with [`::buffa::RECURSION_LIMIT`] - /// and by generated sub-message decode arms with `depth - 1`. + /// Called by [`::buffa::MessageView::decode_view`] with a fresh + /// default context and by generated sub-message decode arms with + /// `ctx.descend()?`. /// /// **Not part of the public API.** Named with a leading underscore to /// signal that it is for generated-code use only. #[doc(hidden)] - pub fn _decode_depth( + pub fn _decode_ctx( buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result { let mut view = Self::default(); - view._merge_into_view(buf, depth)?; + view._merge_into_view(buf, ctx)?; ::core::result::Result::Ok(view) } /// Merge fields from `buf` into this view (proto merge semantics). @@ -42,9 +44,9 @@ impl<'a> EmptyView<'a> { pub fn _merge_into_view( &mut self, buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result<(), ::buffa::DecodeError> { - let _ = depth; + let _ = ctx; #[allow(unused_variables)] let view = self; let mut cur: &'a [u8] = buf; @@ -53,9 +55,9 @@ impl<'a> EmptyView<'a> { let tag = ::buffa::encoding::Tag::decode(&mut cur)?; match tag.field_number() { _ => { - ::buffa::encoding::skip_field_depth(tag, &mut cur, depth)?; + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; let span_len = before_tag.len() - cur.len(); - view.__buffa_unknown_fields.push_raw(&before_tag[..span_len]); + view.__buffa_unknown_fields.push_record(before_tag, span_len, ctx)?; } } } @@ -65,33 +67,35 @@ impl<'a> EmptyView<'a> { impl<'a> ::buffa::MessageView<'a> for EmptyView<'a> { type Owned = super::super::Empty; fn decode_view(buf: &'a [u8]) -> ::core::result::Result { - Self::_decode_depth(buf, ::buffa::RECURSION_LIMIT) + let __limit = ::core::cell::Cell::new(::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT); + Self::_decode_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit), + ) } - fn decode_view_with_limit( + fn decode_view_with_ctx( buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result { - Self::_decode_depth(buf, depth) + Self::_decode_ctx(buf, ctx) } - fn to_owned_message(&self) -> super::super::Empty { + fn to_owned_message( + &self, + ) -> ::core::result::Result { self.to_owned_from_source(None) } #[allow(clippy::useless_conversion, clippy::needless_update)] fn to_owned_from_source( &self, __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, - ) -> super::super::Empty { + ) -> ::core::result::Result { #[allow(unused_imports)] use ::buffa::alloc::string::ToString as _; let _ = __buffa_src; - super::super::Empty { - __buffa_unknown_fields: self - .__buffa_unknown_fields - .to_owned() - .unwrap_or_default() - .into(), + ::core::result::Result::Ok(super::super::Empty { + __buffa_unknown_fields: self.__buffa_unknown_fields.to_owned()?.into(), ..::core::default::Default::default() - } + }) } } impl<'a> ::buffa::ViewEncode<'a> for EmptyView<'a> { @@ -192,8 +196,14 @@ impl EmptyOwnedView { self.0.reborrow() } /// Convert to the owned message type. - #[must_use] - pub fn to_owned_message(&self) -> super::super::Empty { + /// + /// # 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 { self.0.to_owned_message() } /// The underlying bytes buffer. diff --git a/buffa-types/src/generated/google.protobuf.empty.rs b/buffa-types/src/generated/google.protobuf.empty.rs index eb74acd1..3953279f 100644 --- a/buffa-types/src/generated/google.protobuf.empty.rs +++ b/buffa-types/src/generated/google.protobuf.empty.rs @@ -162,7 +162,7 @@ impl ::buffa::Message for Empty { &mut self, tag: ::buffa::encoding::Tag, buf: &mut impl ::buffa::bytes::Buf, - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result<(), ::buffa::DecodeError> { #[allow(unused_imports)] use ::buffa::bytes::Buf as _; @@ -171,7 +171,7 @@ impl ::buffa::Message for Empty { match tag.field_number() { _ => { self.__buffa_unknown_fields - .push(::buffa::encoding::decode_unknown_field(tag, buf, depth)?); + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); } } ::core::result::Result::Ok(()) 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 29a17fae..9b0241c0 100644 --- a/buffa-types/src/generated/google.protobuf.field_mask.__view.rs +++ b/buffa-types/src/generated/google.protobuf.field_mask.__view.rs @@ -233,20 +233,22 @@ pub struct FieldMaskView<'a> { pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, } impl<'a> FieldMaskView<'a> { - /// Decode from `buf`, enforcing a recursion depth limit for nested messages. + /// Decode from `buf` under the limits carried by `ctx` (recursion + /// depth and the shared unknown-field allowance). /// - /// Called by [`::buffa::MessageView::decode_view`] with [`::buffa::RECURSION_LIMIT`] - /// and by generated sub-message decode arms with `depth - 1`. + /// Called by [`::buffa::MessageView::decode_view`] with a fresh + /// default context and by generated sub-message decode arms with + /// `ctx.descend()?`. /// /// **Not part of the public API.** Named with a leading underscore to /// signal that it is for generated-code use only. #[doc(hidden)] - pub fn _decode_depth( + pub fn _decode_ctx( buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result { let mut view = Self::default(); - view._merge_into_view(buf, depth)?; + view._merge_into_view(buf, ctx)?; ::core::result::Result::Ok(view) } /// Merge fields from `buf` into this view (proto merge semantics). @@ -260,9 +262,9 @@ impl<'a> FieldMaskView<'a> { pub fn _merge_into_view( &mut self, buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result<(), ::buffa::DecodeError> { - let _ = depth; + let _ = ctx; #[allow(unused_variables)] let view = self; let mut cur: &'a [u8] = buf; @@ -281,9 +283,9 @@ impl<'a> FieldMaskView<'a> { view.paths.push(::buffa::types::borrow_str(&mut cur)?); } _ => { - ::buffa::encoding::skip_field_depth(tag, &mut cur, depth)?; + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; let span_len = before_tag.len() - cur.len(); - view.__buffa_unknown_fields.push_raw(&before_tag[..span_len]); + view.__buffa_unknown_fields.push_record(before_tag, span_len, ctx)?; } } } @@ -293,34 +295,36 @@ impl<'a> FieldMaskView<'a> { impl<'a> ::buffa::MessageView<'a> for FieldMaskView<'a> { type Owned = super::super::FieldMask; fn decode_view(buf: &'a [u8]) -> ::core::result::Result { - Self::_decode_depth(buf, ::buffa::RECURSION_LIMIT) + let __limit = ::core::cell::Cell::new(::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT); + Self::_decode_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit), + ) } - fn decode_view_with_limit( + fn decode_view_with_ctx( buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result { - Self::_decode_depth(buf, depth) + Self::_decode_ctx(buf, ctx) } - fn to_owned_message(&self) -> super::super::FieldMask { + fn to_owned_message( + &self, + ) -> ::core::result::Result { self.to_owned_from_source(None) } #[allow(clippy::useless_conversion, clippy::needless_update)] fn to_owned_from_source( &self, __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, - ) -> super::super::FieldMask { + ) -> ::core::result::Result { #[allow(unused_imports)] use ::buffa::alloc::string::ToString as _; let _ = __buffa_src; - super::super::FieldMask { + ::core::result::Result::Ok(super::super::FieldMask { paths: self.paths.iter().map(|s| s.to_string()).collect(), - __buffa_unknown_fields: self - .__buffa_unknown_fields - .to_owned() - .unwrap_or_default() - .into(), + __buffa_unknown_fields: self.__buffa_unknown_fields.to_owned()?.into(), ..::core::default::Default::default() - } + }) } } impl<'a> ::buffa::ViewEncode<'a> for FieldMaskView<'a> { @@ -436,8 +440,14 @@ impl FieldMaskOwnedView { self.0.reborrow() } /// Convert to the owned message type. - #[must_use] - pub fn to_owned_message(&self) -> super::super::FieldMask { + /// + /// # 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 { self.0.to_owned_message() } /// The underlying bytes buffer. diff --git a/buffa-types/src/generated/google.protobuf.field_mask.rs b/buffa-types/src/generated/google.protobuf.field_mask.rs index 7fb1a4e5..a54ff9df 100644 --- a/buffa-types/src/generated/google.protobuf.field_mask.rs +++ b/buffa-types/src/generated/google.protobuf.field_mask.rs @@ -393,7 +393,7 @@ impl ::buffa::Message for FieldMask { &mut self, tag: ::buffa::encoding::Tag, buf: &mut impl ::buffa::bytes::Buf, - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result<(), ::buffa::DecodeError> { #[allow(unused_imports)] use ::buffa::bytes::Buf as _; @@ -412,7 +412,7 @@ impl ::buffa::Message for FieldMask { } _ => { self.__buffa_unknown_fields - .push(::buffa::encoding::decode_unknown_field(tag, buf, depth)?); + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); } } ::core::result::Result::Ok(()) diff --git a/buffa-types/src/generated/google.protobuf.struct.__view.rs b/buffa-types/src/generated/google.protobuf.struct.__view.rs index d576ce4d..d07fa12d 100644 --- a/buffa-types/src/generated/google.protobuf.struct.__view.rs +++ b/buffa-types/src/generated/google.protobuf.struct.__view.rs @@ -22,20 +22,22 @@ pub struct StructView<'a> { pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, } impl<'a> StructView<'a> { - /// Decode from `buf`, enforcing a recursion depth limit for nested messages. + /// Decode from `buf` under the limits carried by `ctx` (recursion + /// depth and the shared unknown-field allowance). /// - /// Called by [`::buffa::MessageView::decode_view`] with [`::buffa::RECURSION_LIMIT`] - /// and by generated sub-message decode arms with `depth - 1`. + /// Called by [`::buffa::MessageView::decode_view`] with a fresh + /// default context and by generated sub-message decode arms with + /// `ctx.descend()?`. /// /// **Not part of the public API.** Named with a leading underscore to /// signal that it is for generated-code use only. #[doc(hidden)] - pub fn _decode_depth( + pub fn _decode_ctx( buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result { let mut view = Self::default(); - view._merge_into_view(buf, depth)?; + view._merge_into_view(buf, ctx)?; ::core::result::Result::Ok(view) } /// Merge fields from `buf` into this view (proto merge semantics). @@ -49,9 +51,9 @@ impl<'a> StructView<'a> { pub fn _merge_into_view( &mut self, buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result<(), ::buffa::DecodeError> { - let _ = depth; + let _ = ctx; #[allow(unused_variables)] let view = self; let mut cur: &'a [u8] = buf; @@ -96,20 +98,18 @@ impl<'a> StructView<'a> { actual: entry_tag.wire_type() as u8, }); } - if depth == 0 { - return Err(::buffa::DecodeError::RecursionLimitExceeded); - } + let __sub_ctx = ctx.descend()?; let sub = ::buffa::types::borrow_bytes(&mut entry_cur)?; - val = super::super::__buffa::view::ValueView::_decode_depth( + val = super::super::__buffa::view::ValueView::_decode_ctx( sub, - depth - 1, + __sub_ctx, )?; } _ => { ::buffa::encoding::skip_field_depth( entry_tag, &mut entry_cur, - depth, + ctx.depth(), )?; } } @@ -117,9 +117,9 @@ impl<'a> StructView<'a> { view.fields.push(key, val); } _ => { - ::buffa::encoding::skip_field_depth(tag, &mut cur, depth)?; + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; let span_len = before_tag.len() - cur.len(); - view.__buffa_unknown_fields.push_raw(&before_tag[..span_len]); + view.__buffa_unknown_fields.push_record(before_tag, span_len, ctx)?; } } } @@ -129,38 +129,45 @@ impl<'a> StructView<'a> { impl<'a> ::buffa::MessageView<'a> for StructView<'a> { type Owned = super::super::Struct; fn decode_view(buf: &'a [u8]) -> ::core::result::Result { - Self::_decode_depth(buf, ::buffa::RECURSION_LIMIT) + let __limit = ::core::cell::Cell::new(::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT); + Self::_decode_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit), + ) } - fn decode_view_with_limit( + fn decode_view_with_ctx( buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result { - Self::_decode_depth(buf, depth) + Self::_decode_ctx(buf, ctx) } - fn to_owned_message(&self) -> super::super::Struct { + fn to_owned_message( + &self, + ) -> ::core::result::Result { self.to_owned_from_source(None) } #[allow(clippy::useless_conversion, clippy::needless_update)] fn to_owned_from_source( &self, __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, - ) -> super::super::Struct { + ) -> ::core::result::Result { #[allow(unused_imports)] use ::buffa::alloc::string::ToString as _; let _ = __buffa_src; - super::super::Struct { + ::core::result::Result::Ok(super::super::Struct { fields: self .fields .iter() - .map(|(k, v)| (k.to_string(), v.to_owned_from_source(__buffa_src))) - .collect(), - __buffa_unknown_fields: self - .__buffa_unknown_fields - .to_owned() - .unwrap_or_default() - .into(), + .map(|(k, v)| { + ::core::result::Result::< + _, + ::buffa::DecodeError, + >::Ok((k.to_string(), v.to_owned_from_source(__buffa_src)?)) + }) + .collect::<::core::result::Result<_, ::buffa::DecodeError>>()?, + __buffa_unknown_fields: self.__buffa_unknown_fields.to_owned()?.into(), ..::core::default::Default::default() - } + }) } } impl<'a> ::buffa::ViewEncode<'a> for StructView<'a> { @@ -300,8 +307,14 @@ impl StructOwnedView { self.0.reborrow() } /// Convert to the owned message type. - #[must_use] - pub fn to_owned_message(&self) -> super::super::Struct { + /// + /// # 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 { self.0.to_owned_message() } /// The underlying bytes buffer. @@ -448,20 +461,22 @@ pub struct ValueView<'a> { pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, } impl<'a> ValueView<'a> { - /// Decode from `buf`, enforcing a recursion depth limit for nested messages. + /// Decode from `buf` under the limits carried by `ctx` (recursion + /// depth and the shared unknown-field allowance). /// - /// Called by [`::buffa::MessageView::decode_view`] with [`::buffa::RECURSION_LIMIT`] - /// and by generated sub-message decode arms with `depth - 1`. + /// Called by [`::buffa::MessageView::decode_view`] with a fresh + /// default context and by generated sub-message decode arms with + /// `ctx.descend()?`. /// /// **Not part of the public API.** Named with a leading underscore to /// signal that it is for generated-code use only. #[doc(hidden)] - pub fn _decode_depth( + pub fn _decode_ctx( buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result { let mut view = Self::default(); - view._merge_into_view(buf, depth)?; + view._merge_into_view(buf, ctx)?; ::core::result::Result::Ok(view) } /// Merge fields from `buf` into this view (proto merge semantics). @@ -475,9 +490,9 @@ impl<'a> ValueView<'a> { pub fn _merge_into_view( &mut self, buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result<(), ::buffa::DecodeError> { - let _ = depth; + let _ = ctx; #[allow(unused_variables)] let view = self; let mut cur: &'a [u8] = buf; @@ -551,9 +566,7 @@ impl<'a> ValueView<'a> { actual: tag.wire_type() as u8, }); } - if depth == 0 { - return Err(::buffa::DecodeError::RecursionLimitExceeded); - } + let __sub_ctx = ctx.descend()?; let sub = ::buffa::types::borrow_bytes(&mut cur)?; if let Some( super::super::__buffa::view::oneof::value::Kind::StructValue( @@ -561,14 +574,14 @@ impl<'a> ValueView<'a> { ), ) = view.kind { - existing._merge_into_view(sub, depth - 1)?; + existing._merge_into_view(sub, __sub_ctx)?; } else { view.kind = Some( super::super::__buffa::view::oneof::value::Kind::StructValue( ::buffa::alloc::boxed::Box::new( - super::super::__buffa::view::StructView::_decode_depth( + super::super::__buffa::view::StructView::_decode_ctx( sub, - depth - 1, + __sub_ctx, )?, ), ), @@ -583,9 +596,7 @@ impl<'a> ValueView<'a> { actual: tag.wire_type() as u8, }); } - if depth == 0 { - return Err(::buffa::DecodeError::RecursionLimitExceeded); - } + let __sub_ctx = ctx.descend()?; let sub = ::buffa::types::borrow_bytes(&mut cur)?; if let Some( super::super::__buffa::view::oneof::value::Kind::ListValue( @@ -593,14 +604,14 @@ impl<'a> ValueView<'a> { ), ) = view.kind { - existing._merge_into_view(sub, depth - 1)?; + existing._merge_into_view(sub, __sub_ctx)?; } else { view.kind = Some( super::super::__buffa::view::oneof::value::Kind::ListValue( ::buffa::alloc::boxed::Box::new( - super::super::__buffa::view::ListValueView::_decode_depth( + super::super::__buffa::view::ListValueView::_decode_ctx( sub, - depth - 1, + __sub_ctx, )?, ), ), @@ -608,9 +619,9 @@ impl<'a> ValueView<'a> { } } _ => { - ::buffa::encoding::skip_field_depth(tag, &mut cur, depth)?; + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; let span_len = before_tag.len() - cur.len(); - view.__buffa_unknown_fields.push_raw(&before_tag[..span_len]); + view.__buffa_unknown_fields.push_record(before_tag, span_len, ctx)?; } } } @@ -620,66 +631,80 @@ impl<'a> ValueView<'a> { impl<'a> ::buffa::MessageView<'a> for ValueView<'a> { type Owned = super::super::Value; fn decode_view(buf: &'a [u8]) -> ::core::result::Result { - Self::_decode_depth(buf, ::buffa::RECURSION_LIMIT) + let __limit = ::core::cell::Cell::new(::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT); + Self::_decode_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit), + ) } - fn decode_view_with_limit( + fn decode_view_with_ctx( buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result { - Self::_decode_depth(buf, depth) + Self::_decode_ctx(buf, ctx) } - fn to_owned_message(&self) -> super::super::Value { + fn to_owned_message( + &self, + ) -> ::core::result::Result { self.to_owned_from_source(None) } #[allow(clippy::useless_conversion, clippy::needless_update)] fn to_owned_from_source( &self, __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, - ) -> super::super::Value { + ) -> ::core::result::Result { #[allow(unused_imports)] use ::buffa::alloc::string::ToString as _; let _ = __buffa_src; - super::super::Value { - kind: self - .kind - .as_ref() - .map(|v| match v { - super::super::__buffa::view::oneof::value::Kind::NullValue(v) => { - super::super::__buffa::oneof::value::Kind::NullValue(*v) - } - super::super::__buffa::view::oneof::value::Kind::NumberValue(v) => { - super::super::__buffa::oneof::value::Kind::NumberValue(*v) - } - super::super::__buffa::view::oneof::value::Kind::StringValue(v) => { - super::super::__buffa::oneof::value::Kind::StringValue( - v.to_string(), - ) - } - super::super::__buffa::view::oneof::value::Kind::BoolValue(v) => { - super::super::__buffa::oneof::value::Kind::BoolValue(*v) - } - super::super::__buffa::view::oneof::value::Kind::StructValue(v) => { - super::super::__buffa::oneof::value::Kind::StructValue( - ::buffa::alloc::boxed::Box::new( - v.to_owned_from_source(__buffa_src), - ), - ) - } - super::super::__buffa::view::oneof::value::Kind::ListValue(v) => { - super::super::__buffa::oneof::value::Kind::ListValue( - ::buffa::alloc::boxed::Box::new( - v.to_owned_from_source(__buffa_src), - ), - ) - } - }), - __buffa_unknown_fields: self - .__buffa_unknown_fields - .to_owned() - .unwrap_or_default() - .into(), + ::core::result::Result::Ok(super::super::Value { + kind: match self.kind.as_ref() { + ::core::option::Option::Some(v) => { + ::core::option::Option::Some( + match v { + super::super::__buffa::view::oneof::value::Kind::NullValue( + v, + ) => super::super::__buffa::oneof::value::Kind::NullValue(*v), + super::super::__buffa::view::oneof::value::Kind::NumberValue( + v, + ) => { + super::super::__buffa::oneof::value::Kind::NumberValue(*v) + } + super::super::__buffa::view::oneof::value::Kind::StringValue( + v, + ) => { + super::super::__buffa::oneof::value::Kind::StringValue( + v.to_string(), + ) + } + super::super::__buffa::view::oneof::value::Kind::BoolValue( + v, + ) => super::super::__buffa::oneof::value::Kind::BoolValue(*v), + super::super::__buffa::view::oneof::value::Kind::StructValue( + v, + ) => { + super::super::__buffa::oneof::value::Kind::StructValue( + ::buffa::alloc::boxed::Box::new( + v.to_owned_from_source(__buffa_src)?, + ), + ) + } + super::super::__buffa::view::oneof::value::Kind::ListValue( + v, + ) => { + super::super::__buffa::oneof::value::Kind::ListValue( + ::buffa::alloc::boxed::Box::new( + v.to_owned_from_source(__buffa_src)?, + ), + ) + } + }, + ) + } + ::core::option::Option::None => ::core::option::Option::None, + }, + __buffa_unknown_fields: self.__buffa_unknown_fields.to_owned()?.into(), ..::core::default::Default::default() - } + }) } } impl<'a> ::buffa::ViewEncode<'a> for ValueView<'a> { @@ -866,8 +891,14 @@ impl ValueOwnedView { self.0.reborrow() } /// Convert to the owned message type. - #[must_use] - pub fn to_owned_message(&self) -> super::super::Value { + /// + /// # 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 { self.0.to_owned_message() } /// The underlying bytes buffer. @@ -1123,20 +1154,22 @@ pub struct ListValueView<'a> { pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, } impl<'a> ListValueView<'a> { - /// Decode from `buf`, enforcing a recursion depth limit for nested messages. + /// Decode from `buf` under the limits carried by `ctx` (recursion + /// depth and the shared unknown-field allowance). /// - /// Called by [`::buffa::MessageView::decode_view`] with [`::buffa::RECURSION_LIMIT`] - /// and by generated sub-message decode arms with `depth - 1`. + /// Called by [`::buffa::MessageView::decode_view`] with a fresh + /// default context and by generated sub-message decode arms with + /// `ctx.descend()?`. /// /// **Not part of the public API.** Named with a leading underscore to /// signal that it is for generated-code use only. #[doc(hidden)] - pub fn _decode_depth( + pub fn _decode_ctx( buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result { let mut view = Self::default(); - view._merge_into_view(buf, depth)?; + view._merge_into_view(buf, ctx)?; ::core::result::Result::Ok(view) } /// Merge fields from `buf` into this view (proto merge semantics). @@ -1150,9 +1183,9 @@ impl<'a> ListValueView<'a> { pub fn _merge_into_view( &mut self, buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result<(), ::buffa::DecodeError> { - let _ = depth; + let _ = ctx; #[allow(unused_variables)] let view = self; let mut cur: &'a [u8] = buf; @@ -1168,22 +1201,20 @@ impl<'a> ListValueView<'a> { actual: tag.wire_type() as u8, }); } - if depth == 0 { - return Err(::buffa::DecodeError::RecursionLimitExceeded); - } + let __sub_ctx = ctx.descend()?; let sub = ::buffa::types::borrow_bytes(&mut cur)?; view.values .push( - super::super::__buffa::view::ValueView::_decode_depth( + super::super::__buffa::view::ValueView::_decode_ctx( sub, - depth - 1, + __sub_ctx, )?, ); } _ => { - ::buffa::encoding::skip_field_depth(tag, &mut cur, depth)?; + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; let span_len = before_tag.len() - cur.len(); - view.__buffa_unknown_fields.push_raw(&before_tag[..span_len]); + view.__buffa_unknown_fields.push_record(before_tag, span_len, ctx)?; } } } @@ -1193,38 +1224,40 @@ impl<'a> ListValueView<'a> { impl<'a> ::buffa::MessageView<'a> for ListValueView<'a> { type Owned = super::super::ListValue; fn decode_view(buf: &'a [u8]) -> ::core::result::Result { - Self::_decode_depth(buf, ::buffa::RECURSION_LIMIT) + let __limit = ::core::cell::Cell::new(::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT); + Self::_decode_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit), + ) } - fn decode_view_with_limit( + fn decode_view_with_ctx( buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result { - Self::_decode_depth(buf, depth) + Self::_decode_ctx(buf, ctx) } - fn to_owned_message(&self) -> super::super::ListValue { + fn to_owned_message( + &self, + ) -> ::core::result::Result { self.to_owned_from_source(None) } #[allow(clippy::useless_conversion, clippy::needless_update)] fn to_owned_from_source( &self, __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, - ) -> super::super::ListValue { + ) -> ::core::result::Result { #[allow(unused_imports)] use ::buffa::alloc::string::ToString as _; let _ = __buffa_src; - super::super::ListValue { + ::core::result::Result::Ok(super::super::ListValue { values: self .values .iter() .map(|v| v.to_owned_from_source(__buffa_src)) - .collect(), - __buffa_unknown_fields: self - .__buffa_unknown_fields - .to_owned() - .unwrap_or_default() - .into(), + .collect::<::core::result::Result<_, ::buffa::DecodeError>>()?, + __buffa_unknown_fields: self.__buffa_unknown_fields.to_owned()?.into(), ..::core::default::Default::default() - } + }) } } impl<'a> ::buffa::ViewEncode<'a> for ListValueView<'a> { @@ -1346,8 +1379,14 @@ impl ListValueOwnedView { self.0.reborrow() } /// Convert to the owned message type. - #[must_use] - pub fn to_owned_message(&self) -> super::super::ListValue { + /// + /// # 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 { self.0.to_owned_message() } /// The underlying bytes buffer. diff --git a/buffa-types/src/generated/google.protobuf.struct.rs b/buffa-types/src/generated/google.protobuf.struct.rs index f3e13a25..ee34746d 100644 --- a/buffa-types/src/generated/google.protobuf.struct.rs +++ b/buffa-types/src/generated/google.protobuf.struct.rs @@ -252,7 +252,7 @@ impl ::buffa::Message for Struct { &mut self, tag: ::buffa::encoding::Tag, buf: &mut impl ::buffa::bytes::Buf, - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result<(), ::buffa::DecodeError> { #[allow(unused_imports)] use ::buffa::bytes::Buf as _; @@ -306,11 +306,15 @@ impl ::buffa::Message for Struct { ::buffa::Message::merge_length_delimited( &mut val, buf, - depth, + ctx, )?; } _ => { - ::buffa::encoding::skip_field_depth(entry_tag, buf, depth)?; + ::buffa::encoding::skip_field_depth( + entry_tag, + buf, + ctx.depth(), + )?; } } } @@ -328,7 +332,7 @@ impl ::buffa::Message for Struct { } _ => { self.__buffa_unknown_fields - .push(::buffa::encoding::decode_unknown_field(tag, buf, depth)?); + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); } } ::core::result::Result::Ok(()) @@ -777,7 +781,7 @@ impl ::buffa::Message for Value { &mut self, tag: ::buffa::encoding::Tag, buf: &mut impl ::buffa::bytes::Buf, - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result<(), ::buffa::DecodeError> { #[allow(unused_imports)] use ::buffa::bytes::Buf as _; @@ -852,14 +856,10 @@ impl ::buffa::Message for Value { __buffa::oneof::value::Kind::StructValue(ref mut existing), ) = self.kind { - ::buffa::Message::merge_length_delimited( - &mut **existing, - buf, - depth, - )?; + ::buffa::Message::merge_length_delimited(&mut **existing, buf, ctx)?; } else { let mut val = ::core::default::Default::default(); - ::buffa::Message::merge_length_delimited(&mut val, buf, depth)?; + ::buffa::Message::merge_length_delimited(&mut val, buf, ctx)?; self.kind = ::core::option::Option::Some( __buffa::oneof::value::Kind::StructValue( ::buffa::alloc::boxed::Box::new(val), @@ -879,14 +879,10 @@ impl ::buffa::Message for Value { __buffa::oneof::value::Kind::ListValue(ref mut existing), ) = self.kind { - ::buffa::Message::merge_length_delimited( - &mut **existing, - buf, - depth, - )?; + ::buffa::Message::merge_length_delimited(&mut **existing, buf, ctx)?; } else { let mut val = ::core::default::Default::default(); - ::buffa::Message::merge_length_delimited(&mut val, buf, depth)?; + ::buffa::Message::merge_length_delimited(&mut val, buf, ctx)?; self.kind = ::core::option::Option::Some( __buffa::oneof::value::Kind::ListValue( ::buffa::alloc::boxed::Box::new(val), @@ -896,7 +892,7 @@ impl ::buffa::Message for Value { } _ => { self.__buffa_unknown_fields - .push(::buffa::encoding::decode_unknown_field(tag, buf, depth)?); + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); } } ::core::result::Result::Ok(()) @@ -1222,7 +1218,7 @@ impl ::buffa::Message for ListValue { &mut self, tag: ::buffa::encoding::Tag, buf: &mut impl ::buffa::bytes::Buf, - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result<(), ::buffa::DecodeError> { #[allow(unused_imports)] use ::buffa::bytes::Buf as _; @@ -1238,12 +1234,12 @@ impl ::buffa::Message for ListValue { }); } let mut elem = ::core::default::Default::default(); - ::buffa::Message::merge_length_delimited(&mut elem, buf, depth)?; + ::buffa::Message::merge_length_delimited(&mut elem, buf, ctx)?; self.values.push(elem); } _ => { self.__buffa_unknown_fields - .push(::buffa::encoding::decode_unknown_field(tag, buf, depth)?); + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); } } ::core::result::Result::Ok(()) diff --git a/buffa-types/src/generated/google.protobuf.timestamp.__view.rs b/buffa-types/src/generated/google.protobuf.timestamp.__view.rs index 9ec0c8ce..6c326c38 100644 --- a/buffa-types/src/generated/google.protobuf.timestamp.__view.rs +++ b/buffa-types/src/generated/google.protobuf.timestamp.__view.rs @@ -120,20 +120,22 @@ pub struct TimestampView<'a> { pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, } impl<'a> TimestampView<'a> { - /// Decode from `buf`, enforcing a recursion depth limit for nested messages. + /// Decode from `buf` under the limits carried by `ctx` (recursion + /// depth and the shared unknown-field allowance). /// - /// Called by [`::buffa::MessageView::decode_view`] with [`::buffa::RECURSION_LIMIT`] - /// and by generated sub-message decode arms with `depth - 1`. + /// Called by [`::buffa::MessageView::decode_view`] with a fresh + /// default context and by generated sub-message decode arms with + /// `ctx.descend()?`. /// /// **Not part of the public API.** Named with a leading underscore to /// signal that it is for generated-code use only. #[doc(hidden)] - pub fn _decode_depth( + pub fn _decode_ctx( buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result { let mut view = Self::default(); - view._merge_into_view(buf, depth)?; + view._merge_into_view(buf, ctx)?; ::core::result::Result::Ok(view) } /// Merge fields from `buf` into this view (proto merge semantics). @@ -147,9 +149,9 @@ impl<'a> TimestampView<'a> { pub fn _merge_into_view( &mut self, buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result<(), ::buffa::DecodeError> { - let _ = depth; + let _ = ctx; #[allow(unused_variables)] let view = self; let mut cur: &'a [u8] = buf; @@ -178,9 +180,9 @@ impl<'a> TimestampView<'a> { view.nanos = ::buffa::types::decode_int32(&mut cur)?; } _ => { - ::buffa::encoding::skip_field_depth(tag, &mut cur, depth)?; + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; let span_len = before_tag.len() - cur.len(); - view.__buffa_unknown_fields.push_raw(&before_tag[..span_len]); + view.__buffa_unknown_fields.push_record(before_tag, span_len, ctx)?; } } } @@ -190,35 +192,37 @@ impl<'a> TimestampView<'a> { impl<'a> ::buffa::MessageView<'a> for TimestampView<'a> { type Owned = super::super::Timestamp; fn decode_view(buf: &'a [u8]) -> ::core::result::Result { - Self::_decode_depth(buf, ::buffa::RECURSION_LIMIT) + let __limit = ::core::cell::Cell::new(::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT); + Self::_decode_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit), + ) } - fn decode_view_with_limit( + fn decode_view_with_ctx( buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result { - Self::_decode_depth(buf, depth) + Self::_decode_ctx(buf, ctx) } - fn to_owned_message(&self) -> super::super::Timestamp { + fn to_owned_message( + &self, + ) -> ::core::result::Result { self.to_owned_from_source(None) } #[allow(clippy::useless_conversion, clippy::needless_update)] fn to_owned_from_source( &self, __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, - ) -> super::super::Timestamp { + ) -> ::core::result::Result { #[allow(unused_imports)] use ::buffa::alloc::string::ToString as _; let _ = __buffa_src; - super::super::Timestamp { + ::core::result::Result::Ok(super::super::Timestamp { seconds: self.seconds, nanos: self.nanos, - __buffa_unknown_fields: self - .__buffa_unknown_fields - .to_owned() - .unwrap_or_default() - .into(), + __buffa_unknown_fields: self.__buffa_unknown_fields.to_owned()?.into(), ..::core::default::Default::default() - } + }) } } impl<'a> ::buffa::ViewEncode<'a> for TimestampView<'a> { @@ -339,8 +343,14 @@ impl TimestampOwnedView { self.0.reborrow() } /// Convert to the owned message type. - #[must_use] - pub fn to_owned_message(&self) -> super::super::Timestamp { + /// + /// # 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 { self.0.to_owned_message() } /// The underlying bytes buffer. diff --git a/buffa-types/src/generated/google.protobuf.timestamp.rs b/buffa-types/src/generated/google.protobuf.timestamp.rs index bd622835..62f87d20 100644 --- a/buffa-types/src/generated/google.protobuf.timestamp.rs +++ b/buffa-types/src/generated/google.protobuf.timestamp.rs @@ -290,7 +290,7 @@ impl ::buffa::Message for Timestamp { &mut self, tag: ::buffa::encoding::Tag, buf: &mut impl ::buffa::bytes::Buf, - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result<(), ::buffa::DecodeError> { #[allow(unused_imports)] use ::buffa::bytes::Buf as _; @@ -319,7 +319,7 @@ impl ::buffa::Message for Timestamp { } _ => { self.__buffa_unknown_fields - .push(::buffa::encoding::decode_unknown_field(tag, buf, depth)?); + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); } } ::core::result::Result::Ok(()) diff --git a/buffa-types/src/generated/google.protobuf.wrappers.__view.rs b/buffa-types/src/generated/google.protobuf.wrappers.__view.rs index 85757fc1..a97b2109 100644 --- a/buffa-types/src/generated/google.protobuf.wrappers.__view.rs +++ b/buffa-types/src/generated/google.protobuf.wrappers.__view.rs @@ -13,20 +13,22 @@ pub struct DoubleValueView<'a> { pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, } impl<'a> DoubleValueView<'a> { - /// Decode from `buf`, enforcing a recursion depth limit for nested messages. + /// Decode from `buf` under the limits carried by `ctx` (recursion + /// depth and the shared unknown-field allowance). /// - /// Called by [`::buffa::MessageView::decode_view`] with [`::buffa::RECURSION_LIMIT`] - /// and by generated sub-message decode arms with `depth - 1`. + /// Called by [`::buffa::MessageView::decode_view`] with a fresh + /// default context and by generated sub-message decode arms with + /// `ctx.descend()?`. /// /// **Not part of the public API.** Named with a leading underscore to /// signal that it is for generated-code use only. #[doc(hidden)] - pub fn _decode_depth( + pub fn _decode_ctx( buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result { let mut view = Self::default(); - view._merge_into_view(buf, depth)?; + view._merge_into_view(buf, ctx)?; ::core::result::Result::Ok(view) } /// Merge fields from `buf` into this view (proto merge semantics). @@ -40,9 +42,9 @@ impl<'a> DoubleValueView<'a> { pub fn _merge_into_view( &mut self, buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result<(), ::buffa::DecodeError> { - let _ = depth; + let _ = ctx; #[allow(unused_variables)] let view = self; let mut cur: &'a [u8] = buf; @@ -61,9 +63,9 @@ impl<'a> DoubleValueView<'a> { view.value = ::buffa::types::decode_double(&mut cur)?; } _ => { - ::buffa::encoding::skip_field_depth(tag, &mut cur, depth)?; + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; let span_len = before_tag.len() - cur.len(); - view.__buffa_unknown_fields.push_raw(&before_tag[..span_len]); + view.__buffa_unknown_fields.push_record(before_tag, span_len, ctx)?; } } } @@ -73,34 +75,36 @@ impl<'a> DoubleValueView<'a> { impl<'a> ::buffa::MessageView<'a> for DoubleValueView<'a> { type Owned = super::super::DoubleValue; fn decode_view(buf: &'a [u8]) -> ::core::result::Result { - Self::_decode_depth(buf, ::buffa::RECURSION_LIMIT) + let __limit = ::core::cell::Cell::new(::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT); + Self::_decode_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit), + ) } - fn decode_view_with_limit( + fn decode_view_with_ctx( buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result { - Self::_decode_depth(buf, depth) + Self::_decode_ctx(buf, ctx) } - fn to_owned_message(&self) -> super::super::DoubleValue { + fn to_owned_message( + &self, + ) -> ::core::result::Result { self.to_owned_from_source(None) } #[allow(clippy::useless_conversion, clippy::needless_update)] fn to_owned_from_source( &self, __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, - ) -> super::super::DoubleValue { + ) -> ::core::result::Result { #[allow(unused_imports)] use ::buffa::alloc::string::ToString as _; let _ = __buffa_src; - super::super::DoubleValue { + ::core::result::Result::Ok(super::super::DoubleValue { value: self.value, - __buffa_unknown_fields: self - .__buffa_unknown_fields - .to_owned() - .unwrap_or_default() - .into(), + __buffa_unknown_fields: self.__buffa_unknown_fields.to_owned()?.into(), ..::core::default::Default::default() - } + }) } } impl<'a> ::buffa::ViewEncode<'a> for DoubleValueView<'a> { @@ -213,8 +217,14 @@ impl DoubleValueOwnedView { self.0.reborrow() } /// Convert to the owned message type. - #[must_use] - pub fn to_owned_message(&self) -> super::super::DoubleValue { + /// + /// # 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 { self.0.to_owned_message() } /// The underlying bytes buffer. @@ -359,20 +369,22 @@ pub struct FloatValueView<'a> { pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, } impl<'a> FloatValueView<'a> { - /// Decode from `buf`, enforcing a recursion depth limit for nested messages. + /// Decode from `buf` under the limits carried by `ctx` (recursion + /// depth and the shared unknown-field allowance). /// - /// Called by [`::buffa::MessageView::decode_view`] with [`::buffa::RECURSION_LIMIT`] - /// and by generated sub-message decode arms with `depth - 1`. + /// Called by [`::buffa::MessageView::decode_view`] with a fresh + /// default context and by generated sub-message decode arms with + /// `ctx.descend()?`. /// /// **Not part of the public API.** Named with a leading underscore to /// signal that it is for generated-code use only. #[doc(hidden)] - pub fn _decode_depth( + pub fn _decode_ctx( buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result { let mut view = Self::default(); - view._merge_into_view(buf, depth)?; + view._merge_into_view(buf, ctx)?; ::core::result::Result::Ok(view) } /// Merge fields from `buf` into this view (proto merge semantics). @@ -386,9 +398,9 @@ impl<'a> FloatValueView<'a> { pub fn _merge_into_view( &mut self, buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result<(), ::buffa::DecodeError> { - let _ = depth; + let _ = ctx; #[allow(unused_variables)] let view = self; let mut cur: &'a [u8] = buf; @@ -407,9 +419,9 @@ impl<'a> FloatValueView<'a> { view.value = ::buffa::types::decode_float(&mut cur)?; } _ => { - ::buffa::encoding::skip_field_depth(tag, &mut cur, depth)?; + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; let span_len = before_tag.len() - cur.len(); - view.__buffa_unknown_fields.push_raw(&before_tag[..span_len]); + view.__buffa_unknown_fields.push_record(before_tag, span_len, ctx)?; } } } @@ -419,34 +431,36 @@ impl<'a> FloatValueView<'a> { impl<'a> ::buffa::MessageView<'a> for FloatValueView<'a> { type Owned = super::super::FloatValue; fn decode_view(buf: &'a [u8]) -> ::core::result::Result { - Self::_decode_depth(buf, ::buffa::RECURSION_LIMIT) + let __limit = ::core::cell::Cell::new(::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT); + Self::_decode_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit), + ) } - fn decode_view_with_limit( + fn decode_view_with_ctx( buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result { - Self::_decode_depth(buf, depth) + Self::_decode_ctx(buf, ctx) } - fn to_owned_message(&self) -> super::super::FloatValue { + fn to_owned_message( + &self, + ) -> ::core::result::Result { self.to_owned_from_source(None) } #[allow(clippy::useless_conversion, clippy::needless_update)] fn to_owned_from_source( &self, __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, - ) -> super::super::FloatValue { + ) -> ::core::result::Result { #[allow(unused_imports)] use ::buffa::alloc::string::ToString as _; let _ = __buffa_src; - super::super::FloatValue { + ::core::result::Result::Ok(super::super::FloatValue { value: self.value, - __buffa_unknown_fields: self - .__buffa_unknown_fields - .to_owned() - .unwrap_or_default() - .into(), + __buffa_unknown_fields: self.__buffa_unknown_fields.to_owned()?.into(), ..::core::default::Default::default() - } + }) } } impl<'a> ::buffa::ViewEncode<'a> for FloatValueView<'a> { @@ -559,8 +573,14 @@ impl FloatValueOwnedView { self.0.reborrow() } /// Convert to the owned message type. - #[must_use] - pub fn to_owned_message(&self) -> super::super::FloatValue { + /// + /// # 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 { self.0.to_owned_message() } /// The underlying bytes buffer. @@ -705,20 +725,22 @@ pub struct Int64ValueView<'a> { pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, } impl<'a> Int64ValueView<'a> { - /// Decode from `buf`, enforcing a recursion depth limit for nested messages. + /// Decode from `buf` under the limits carried by `ctx` (recursion + /// depth and the shared unknown-field allowance). /// - /// Called by [`::buffa::MessageView::decode_view`] with [`::buffa::RECURSION_LIMIT`] - /// and by generated sub-message decode arms with `depth - 1`. + /// Called by [`::buffa::MessageView::decode_view`] with a fresh + /// default context and by generated sub-message decode arms with + /// `ctx.descend()?`. /// /// **Not part of the public API.** Named with a leading underscore to /// signal that it is for generated-code use only. #[doc(hidden)] - pub fn _decode_depth( + pub fn _decode_ctx( buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result { let mut view = Self::default(); - view._merge_into_view(buf, depth)?; + view._merge_into_view(buf, ctx)?; ::core::result::Result::Ok(view) } /// Merge fields from `buf` into this view (proto merge semantics). @@ -732,9 +754,9 @@ impl<'a> Int64ValueView<'a> { pub fn _merge_into_view( &mut self, buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result<(), ::buffa::DecodeError> { - let _ = depth; + let _ = ctx; #[allow(unused_variables)] let view = self; let mut cur: &'a [u8] = buf; @@ -753,9 +775,9 @@ impl<'a> Int64ValueView<'a> { view.value = ::buffa::types::decode_int64(&mut cur)?; } _ => { - ::buffa::encoding::skip_field_depth(tag, &mut cur, depth)?; + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; let span_len = before_tag.len() - cur.len(); - view.__buffa_unknown_fields.push_raw(&before_tag[..span_len]); + view.__buffa_unknown_fields.push_record(before_tag, span_len, ctx)?; } } } @@ -765,34 +787,36 @@ impl<'a> Int64ValueView<'a> { impl<'a> ::buffa::MessageView<'a> for Int64ValueView<'a> { type Owned = super::super::Int64Value; fn decode_view(buf: &'a [u8]) -> ::core::result::Result { - Self::_decode_depth(buf, ::buffa::RECURSION_LIMIT) + let __limit = ::core::cell::Cell::new(::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT); + Self::_decode_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit), + ) } - fn decode_view_with_limit( + fn decode_view_with_ctx( buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result { - Self::_decode_depth(buf, depth) + Self::_decode_ctx(buf, ctx) } - fn to_owned_message(&self) -> super::super::Int64Value { + fn to_owned_message( + &self, + ) -> ::core::result::Result { self.to_owned_from_source(None) } #[allow(clippy::useless_conversion, clippy::needless_update)] fn to_owned_from_source( &self, __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, - ) -> super::super::Int64Value { + ) -> ::core::result::Result { #[allow(unused_imports)] use ::buffa::alloc::string::ToString as _; let _ = __buffa_src; - super::super::Int64Value { + ::core::result::Result::Ok(super::super::Int64Value { value: self.value, - __buffa_unknown_fields: self - .__buffa_unknown_fields - .to_owned() - .unwrap_or_default() - .into(), + __buffa_unknown_fields: self.__buffa_unknown_fields.to_owned()?.into(), ..::core::default::Default::default() - } + }) } } impl<'a> ::buffa::ViewEncode<'a> for Int64ValueView<'a> { @@ -905,8 +929,14 @@ impl Int64ValueOwnedView { self.0.reborrow() } /// Convert to the owned message type. - #[must_use] - pub fn to_owned_message(&self) -> super::super::Int64Value { + /// + /// # 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 { self.0.to_owned_message() } /// The underlying bytes buffer. @@ -1051,20 +1081,22 @@ pub struct UInt64ValueView<'a> { pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, } impl<'a> UInt64ValueView<'a> { - /// Decode from `buf`, enforcing a recursion depth limit for nested messages. + /// Decode from `buf` under the limits carried by `ctx` (recursion + /// depth and the shared unknown-field allowance). /// - /// Called by [`::buffa::MessageView::decode_view`] with [`::buffa::RECURSION_LIMIT`] - /// and by generated sub-message decode arms with `depth - 1`. + /// Called by [`::buffa::MessageView::decode_view`] with a fresh + /// default context and by generated sub-message decode arms with + /// `ctx.descend()?`. /// /// **Not part of the public API.** Named with a leading underscore to /// signal that it is for generated-code use only. #[doc(hidden)] - pub fn _decode_depth( + pub fn _decode_ctx( buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result { let mut view = Self::default(); - view._merge_into_view(buf, depth)?; + view._merge_into_view(buf, ctx)?; ::core::result::Result::Ok(view) } /// Merge fields from `buf` into this view (proto merge semantics). @@ -1078,9 +1110,9 @@ impl<'a> UInt64ValueView<'a> { pub fn _merge_into_view( &mut self, buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result<(), ::buffa::DecodeError> { - let _ = depth; + let _ = ctx; #[allow(unused_variables)] let view = self; let mut cur: &'a [u8] = buf; @@ -1099,9 +1131,9 @@ impl<'a> UInt64ValueView<'a> { view.value = ::buffa::types::decode_uint64(&mut cur)?; } _ => { - ::buffa::encoding::skip_field_depth(tag, &mut cur, depth)?; + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; let span_len = before_tag.len() - cur.len(); - view.__buffa_unknown_fields.push_raw(&before_tag[..span_len]); + view.__buffa_unknown_fields.push_record(before_tag, span_len, ctx)?; } } } @@ -1111,34 +1143,36 @@ impl<'a> UInt64ValueView<'a> { impl<'a> ::buffa::MessageView<'a> for UInt64ValueView<'a> { type Owned = super::super::UInt64Value; fn decode_view(buf: &'a [u8]) -> ::core::result::Result { - Self::_decode_depth(buf, ::buffa::RECURSION_LIMIT) + let __limit = ::core::cell::Cell::new(::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT); + Self::_decode_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit), + ) } - fn decode_view_with_limit( + fn decode_view_with_ctx( buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result { - Self::_decode_depth(buf, depth) + Self::_decode_ctx(buf, ctx) } - fn to_owned_message(&self) -> super::super::UInt64Value { + fn to_owned_message( + &self, + ) -> ::core::result::Result { self.to_owned_from_source(None) } #[allow(clippy::useless_conversion, clippy::needless_update)] fn to_owned_from_source( &self, __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, - ) -> super::super::UInt64Value { + ) -> ::core::result::Result { #[allow(unused_imports)] use ::buffa::alloc::string::ToString as _; let _ = __buffa_src; - super::super::UInt64Value { + ::core::result::Result::Ok(super::super::UInt64Value { value: self.value, - __buffa_unknown_fields: self - .__buffa_unknown_fields - .to_owned() - .unwrap_or_default() - .into(), + __buffa_unknown_fields: self.__buffa_unknown_fields.to_owned()?.into(), ..::core::default::Default::default() - } + }) } } impl<'a> ::buffa::ViewEncode<'a> for UInt64ValueView<'a> { @@ -1251,8 +1285,14 @@ impl UInt64ValueOwnedView { self.0.reborrow() } /// Convert to the owned message type. - #[must_use] - pub fn to_owned_message(&self) -> super::super::UInt64Value { + /// + /// # 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 { self.0.to_owned_message() } /// The underlying bytes buffer. @@ -1397,20 +1437,22 @@ pub struct Int32ValueView<'a> { pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, } impl<'a> Int32ValueView<'a> { - /// Decode from `buf`, enforcing a recursion depth limit for nested messages. + /// Decode from `buf` under the limits carried by `ctx` (recursion + /// depth and the shared unknown-field allowance). /// - /// Called by [`::buffa::MessageView::decode_view`] with [`::buffa::RECURSION_LIMIT`] - /// and by generated sub-message decode arms with `depth - 1`. + /// Called by [`::buffa::MessageView::decode_view`] with a fresh + /// default context and by generated sub-message decode arms with + /// `ctx.descend()?`. /// /// **Not part of the public API.** Named with a leading underscore to /// signal that it is for generated-code use only. #[doc(hidden)] - pub fn _decode_depth( + pub fn _decode_ctx( buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result { let mut view = Self::default(); - view._merge_into_view(buf, depth)?; + view._merge_into_view(buf, ctx)?; ::core::result::Result::Ok(view) } /// Merge fields from `buf` into this view (proto merge semantics). @@ -1424,9 +1466,9 @@ impl<'a> Int32ValueView<'a> { pub fn _merge_into_view( &mut self, buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result<(), ::buffa::DecodeError> { - let _ = depth; + let _ = ctx; #[allow(unused_variables)] let view = self; let mut cur: &'a [u8] = buf; @@ -1445,9 +1487,9 @@ impl<'a> Int32ValueView<'a> { view.value = ::buffa::types::decode_int32(&mut cur)?; } _ => { - ::buffa::encoding::skip_field_depth(tag, &mut cur, depth)?; + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; let span_len = before_tag.len() - cur.len(); - view.__buffa_unknown_fields.push_raw(&before_tag[..span_len]); + view.__buffa_unknown_fields.push_record(before_tag, span_len, ctx)?; } } } @@ -1457,34 +1499,36 @@ impl<'a> Int32ValueView<'a> { impl<'a> ::buffa::MessageView<'a> for Int32ValueView<'a> { type Owned = super::super::Int32Value; fn decode_view(buf: &'a [u8]) -> ::core::result::Result { - Self::_decode_depth(buf, ::buffa::RECURSION_LIMIT) + let __limit = ::core::cell::Cell::new(::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT); + Self::_decode_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit), + ) } - fn decode_view_with_limit( + fn decode_view_with_ctx( buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result { - Self::_decode_depth(buf, depth) + Self::_decode_ctx(buf, ctx) } - fn to_owned_message(&self) -> super::super::Int32Value { + fn to_owned_message( + &self, + ) -> ::core::result::Result { self.to_owned_from_source(None) } #[allow(clippy::useless_conversion, clippy::needless_update)] fn to_owned_from_source( &self, __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, - ) -> super::super::Int32Value { + ) -> ::core::result::Result { #[allow(unused_imports)] use ::buffa::alloc::string::ToString as _; let _ = __buffa_src; - super::super::Int32Value { + ::core::result::Result::Ok(super::super::Int32Value { value: self.value, - __buffa_unknown_fields: self - .__buffa_unknown_fields - .to_owned() - .unwrap_or_default() - .into(), + __buffa_unknown_fields: self.__buffa_unknown_fields.to_owned()?.into(), ..::core::default::Default::default() - } + }) } } impl<'a> ::buffa::ViewEncode<'a> for Int32ValueView<'a> { @@ -1597,8 +1641,14 @@ impl Int32ValueOwnedView { self.0.reborrow() } /// Convert to the owned message type. - #[must_use] - pub fn to_owned_message(&self) -> super::super::Int32Value { + /// + /// # 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 { self.0.to_owned_message() } /// The underlying bytes buffer. @@ -1743,20 +1793,22 @@ pub struct UInt32ValueView<'a> { pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, } impl<'a> UInt32ValueView<'a> { - /// Decode from `buf`, enforcing a recursion depth limit for nested messages. + /// Decode from `buf` under the limits carried by `ctx` (recursion + /// depth and the shared unknown-field allowance). /// - /// Called by [`::buffa::MessageView::decode_view`] with [`::buffa::RECURSION_LIMIT`] - /// and by generated sub-message decode arms with `depth - 1`. + /// Called by [`::buffa::MessageView::decode_view`] with a fresh + /// default context and by generated sub-message decode arms with + /// `ctx.descend()?`. /// /// **Not part of the public API.** Named with a leading underscore to /// signal that it is for generated-code use only. #[doc(hidden)] - pub fn _decode_depth( + pub fn _decode_ctx( buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result { let mut view = Self::default(); - view._merge_into_view(buf, depth)?; + view._merge_into_view(buf, ctx)?; ::core::result::Result::Ok(view) } /// Merge fields from `buf` into this view (proto merge semantics). @@ -1770,9 +1822,9 @@ impl<'a> UInt32ValueView<'a> { pub fn _merge_into_view( &mut self, buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result<(), ::buffa::DecodeError> { - let _ = depth; + let _ = ctx; #[allow(unused_variables)] let view = self; let mut cur: &'a [u8] = buf; @@ -1791,9 +1843,9 @@ impl<'a> UInt32ValueView<'a> { view.value = ::buffa::types::decode_uint32(&mut cur)?; } _ => { - ::buffa::encoding::skip_field_depth(tag, &mut cur, depth)?; + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; let span_len = before_tag.len() - cur.len(); - view.__buffa_unknown_fields.push_raw(&before_tag[..span_len]); + view.__buffa_unknown_fields.push_record(before_tag, span_len, ctx)?; } } } @@ -1803,34 +1855,36 @@ impl<'a> UInt32ValueView<'a> { impl<'a> ::buffa::MessageView<'a> for UInt32ValueView<'a> { type Owned = super::super::UInt32Value; fn decode_view(buf: &'a [u8]) -> ::core::result::Result { - Self::_decode_depth(buf, ::buffa::RECURSION_LIMIT) + let __limit = ::core::cell::Cell::new(::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT); + Self::_decode_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit), + ) } - fn decode_view_with_limit( + fn decode_view_with_ctx( buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result { - Self::_decode_depth(buf, depth) + Self::_decode_ctx(buf, ctx) } - fn to_owned_message(&self) -> super::super::UInt32Value { + fn to_owned_message( + &self, + ) -> ::core::result::Result { self.to_owned_from_source(None) } #[allow(clippy::useless_conversion, clippy::needless_update)] fn to_owned_from_source( &self, __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, - ) -> super::super::UInt32Value { + ) -> ::core::result::Result { #[allow(unused_imports)] use ::buffa::alloc::string::ToString as _; let _ = __buffa_src; - super::super::UInt32Value { + ::core::result::Result::Ok(super::super::UInt32Value { value: self.value, - __buffa_unknown_fields: self - .__buffa_unknown_fields - .to_owned() - .unwrap_or_default() - .into(), + __buffa_unknown_fields: self.__buffa_unknown_fields.to_owned()?.into(), ..::core::default::Default::default() - } + }) } } impl<'a> ::buffa::ViewEncode<'a> for UInt32ValueView<'a> { @@ -1943,8 +1997,14 @@ impl UInt32ValueOwnedView { self.0.reborrow() } /// Convert to the owned message type. - #[must_use] - pub fn to_owned_message(&self) -> super::super::UInt32Value { + /// + /// # 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 { self.0.to_owned_message() } /// The underlying bytes buffer. @@ -2089,20 +2149,22 @@ pub struct BoolValueView<'a> { pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, } impl<'a> BoolValueView<'a> { - /// Decode from `buf`, enforcing a recursion depth limit for nested messages. + /// Decode from `buf` under the limits carried by `ctx` (recursion + /// depth and the shared unknown-field allowance). /// - /// Called by [`::buffa::MessageView::decode_view`] with [`::buffa::RECURSION_LIMIT`] - /// and by generated sub-message decode arms with `depth - 1`. + /// Called by [`::buffa::MessageView::decode_view`] with a fresh + /// default context and by generated sub-message decode arms with + /// `ctx.descend()?`. /// /// **Not part of the public API.** Named with a leading underscore to /// signal that it is for generated-code use only. #[doc(hidden)] - pub fn _decode_depth( + pub fn _decode_ctx( buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result { let mut view = Self::default(); - view._merge_into_view(buf, depth)?; + view._merge_into_view(buf, ctx)?; ::core::result::Result::Ok(view) } /// Merge fields from `buf` into this view (proto merge semantics). @@ -2116,9 +2178,9 @@ impl<'a> BoolValueView<'a> { pub fn _merge_into_view( &mut self, buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result<(), ::buffa::DecodeError> { - let _ = depth; + let _ = ctx; #[allow(unused_variables)] let view = self; let mut cur: &'a [u8] = buf; @@ -2137,9 +2199,9 @@ impl<'a> BoolValueView<'a> { view.value = ::buffa::types::decode_bool(&mut cur)?; } _ => { - ::buffa::encoding::skip_field_depth(tag, &mut cur, depth)?; + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; let span_len = before_tag.len() - cur.len(); - view.__buffa_unknown_fields.push_raw(&before_tag[..span_len]); + view.__buffa_unknown_fields.push_record(before_tag, span_len, ctx)?; } } } @@ -2149,34 +2211,36 @@ impl<'a> BoolValueView<'a> { impl<'a> ::buffa::MessageView<'a> for BoolValueView<'a> { type Owned = super::super::BoolValue; fn decode_view(buf: &'a [u8]) -> ::core::result::Result { - Self::_decode_depth(buf, ::buffa::RECURSION_LIMIT) + let __limit = ::core::cell::Cell::new(::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT); + Self::_decode_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit), + ) } - fn decode_view_with_limit( + fn decode_view_with_ctx( buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result { - Self::_decode_depth(buf, depth) + Self::_decode_ctx(buf, ctx) } - fn to_owned_message(&self) -> super::super::BoolValue { + fn to_owned_message( + &self, + ) -> ::core::result::Result { self.to_owned_from_source(None) } #[allow(clippy::useless_conversion, clippy::needless_update)] fn to_owned_from_source( &self, __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, - ) -> super::super::BoolValue { + ) -> ::core::result::Result { #[allow(unused_imports)] use ::buffa::alloc::string::ToString as _; let _ = __buffa_src; - super::super::BoolValue { + ::core::result::Result::Ok(super::super::BoolValue { value: self.value, - __buffa_unknown_fields: self - .__buffa_unknown_fields - .to_owned() - .unwrap_or_default() - .into(), + __buffa_unknown_fields: self.__buffa_unknown_fields.to_owned()?.into(), ..::core::default::Default::default() - } + }) } } impl<'a> ::buffa::ViewEncode<'a> for BoolValueView<'a> { @@ -2289,8 +2353,14 @@ impl BoolValueOwnedView { self.0.reborrow() } /// Convert to the owned message type. - #[must_use] - pub fn to_owned_message(&self) -> super::super::BoolValue { + /// + /// # 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 { self.0.to_owned_message() } /// The underlying bytes buffer. @@ -2435,20 +2505,22 @@ pub struct StringValueView<'a> { pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, } impl<'a> StringValueView<'a> { - /// Decode from `buf`, enforcing a recursion depth limit for nested messages. + /// Decode from `buf` under the limits carried by `ctx` (recursion + /// depth and the shared unknown-field allowance). /// - /// Called by [`::buffa::MessageView::decode_view`] with [`::buffa::RECURSION_LIMIT`] - /// and by generated sub-message decode arms with `depth - 1`. + /// Called by [`::buffa::MessageView::decode_view`] with a fresh + /// default context and by generated sub-message decode arms with + /// `ctx.descend()?`. /// /// **Not part of the public API.** Named with a leading underscore to /// signal that it is for generated-code use only. #[doc(hidden)] - pub fn _decode_depth( + pub fn _decode_ctx( buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result { let mut view = Self::default(); - view._merge_into_view(buf, depth)?; + view._merge_into_view(buf, ctx)?; ::core::result::Result::Ok(view) } /// Merge fields from `buf` into this view (proto merge semantics). @@ -2462,9 +2534,9 @@ impl<'a> StringValueView<'a> { pub fn _merge_into_view( &mut self, buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result<(), ::buffa::DecodeError> { - let _ = depth; + let _ = ctx; #[allow(unused_variables)] let view = self; let mut cur: &'a [u8] = buf; @@ -2483,9 +2555,9 @@ impl<'a> StringValueView<'a> { view.value = ::buffa::types::borrow_str(&mut cur)?; } _ => { - ::buffa::encoding::skip_field_depth(tag, &mut cur, depth)?; + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; let span_len = before_tag.len() - cur.len(); - view.__buffa_unknown_fields.push_raw(&before_tag[..span_len]); + view.__buffa_unknown_fields.push_record(before_tag, span_len, ctx)?; } } } @@ -2495,34 +2567,36 @@ impl<'a> StringValueView<'a> { impl<'a> ::buffa::MessageView<'a> for StringValueView<'a> { type Owned = super::super::StringValue; fn decode_view(buf: &'a [u8]) -> ::core::result::Result { - Self::_decode_depth(buf, ::buffa::RECURSION_LIMIT) + let __limit = ::core::cell::Cell::new(::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT); + Self::_decode_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit), + ) } - fn decode_view_with_limit( + fn decode_view_with_ctx( buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result { - Self::_decode_depth(buf, depth) + Self::_decode_ctx(buf, ctx) } - fn to_owned_message(&self) -> super::super::StringValue { + fn to_owned_message( + &self, + ) -> ::core::result::Result { self.to_owned_from_source(None) } #[allow(clippy::useless_conversion, clippy::needless_update)] fn to_owned_from_source( &self, __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, - ) -> super::super::StringValue { + ) -> ::core::result::Result { #[allow(unused_imports)] use ::buffa::alloc::string::ToString as _; let _ = __buffa_src; - super::super::StringValue { + ::core::result::Result::Ok(super::super::StringValue { value: self.value.to_string(), - __buffa_unknown_fields: self - .__buffa_unknown_fields - .to_owned() - .unwrap_or_default() - .into(), + __buffa_unknown_fields: self.__buffa_unknown_fields.to_owned()?.into(), ..::core::default::Default::default() - } + }) } } impl<'a> ::buffa::ViewEncode<'a> for StringValueView<'a> { @@ -2638,8 +2712,14 @@ impl StringValueOwnedView { self.0.reborrow() } /// Convert to the owned message type. - #[must_use] - pub fn to_owned_message(&self) -> super::super::StringValue { + /// + /// # 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 { self.0.to_owned_message() } /// The underlying bytes buffer. @@ -2784,20 +2864,22 @@ pub struct BytesValueView<'a> { pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, } impl<'a> BytesValueView<'a> { - /// Decode from `buf`, enforcing a recursion depth limit for nested messages. + /// Decode from `buf` under the limits carried by `ctx` (recursion + /// depth and the shared unknown-field allowance). /// - /// Called by [`::buffa::MessageView::decode_view`] with [`::buffa::RECURSION_LIMIT`] - /// and by generated sub-message decode arms with `depth - 1`. + /// Called by [`::buffa::MessageView::decode_view`] with a fresh + /// default context and by generated sub-message decode arms with + /// `ctx.descend()?`. /// /// **Not part of the public API.** Named with a leading underscore to /// signal that it is for generated-code use only. #[doc(hidden)] - pub fn _decode_depth( + pub fn _decode_ctx( buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result { let mut view = Self::default(); - view._merge_into_view(buf, depth)?; + view._merge_into_view(buf, ctx)?; ::core::result::Result::Ok(view) } /// Merge fields from `buf` into this view (proto merge semantics). @@ -2811,9 +2893,9 @@ impl<'a> BytesValueView<'a> { pub fn _merge_into_view( &mut self, buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result<(), ::buffa::DecodeError> { - let _ = depth; + let _ = ctx; #[allow(unused_variables)] let view = self; let mut cur: &'a [u8] = buf; @@ -2832,9 +2914,9 @@ impl<'a> BytesValueView<'a> { view.value = ::buffa::types::borrow_bytes(&mut cur)?; } _ => { - ::buffa::encoding::skip_field_depth(tag, &mut cur, depth)?; + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; let span_len = before_tag.len() - cur.len(); - view.__buffa_unknown_fields.push_raw(&before_tag[..span_len]); + view.__buffa_unknown_fields.push_record(before_tag, span_len, ctx)?; } } } @@ -2844,34 +2926,36 @@ impl<'a> BytesValueView<'a> { impl<'a> ::buffa::MessageView<'a> for BytesValueView<'a> { type Owned = super::super::BytesValue; fn decode_view(buf: &'a [u8]) -> ::core::result::Result { - Self::_decode_depth(buf, ::buffa::RECURSION_LIMIT) + let __limit = ::core::cell::Cell::new(::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT); + Self::_decode_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit), + ) } - fn decode_view_with_limit( + fn decode_view_with_ctx( buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result { - Self::_decode_depth(buf, depth) + Self::_decode_ctx(buf, ctx) } - fn to_owned_message(&self) -> super::super::BytesValue { + fn to_owned_message( + &self, + ) -> ::core::result::Result { self.to_owned_from_source(None) } #[allow(clippy::useless_conversion, clippy::needless_update)] fn to_owned_from_source( &self, __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, - ) -> super::super::BytesValue { + ) -> ::core::result::Result { #[allow(unused_imports)] use ::buffa::alloc::string::ToString as _; let _ = __buffa_src; - super::super::BytesValue { + ::core::result::Result::Ok(super::super::BytesValue { value: (self.value).to_vec(), - __buffa_unknown_fields: self - .__buffa_unknown_fields - .to_owned() - .unwrap_or_default() - .into(), + __buffa_unknown_fields: self.__buffa_unknown_fields.to_owned()?.into(), ..::core::default::Default::default() - } + }) } } impl<'a> ::buffa::ViewEncode<'a> for BytesValueView<'a> { @@ -2987,8 +3071,14 @@ impl BytesValueOwnedView { self.0.reborrow() } /// Convert to the owned message type. - #[must_use] - pub fn to_owned_message(&self) -> super::super::BytesValue { + /// + /// # 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 { self.0.to_owned_message() } /// The underlying bytes buffer. diff --git a/buffa-types/src/generated/google.protobuf.wrappers.rs b/buffa-types/src/generated/google.protobuf.wrappers.rs index 8c4013ff..155421d2 100644 --- a/buffa-types/src/generated/google.protobuf.wrappers.rs +++ b/buffa-types/src/generated/google.protobuf.wrappers.rs @@ -170,7 +170,7 @@ impl ::buffa::Message for DoubleValue { &mut self, tag: ::buffa::encoding::Tag, buf: &mut impl ::buffa::bytes::Buf, - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result<(), ::buffa::DecodeError> { #[allow(unused_imports)] use ::buffa::bytes::Buf as _; @@ -189,7 +189,7 @@ impl ::buffa::Message for DoubleValue { } _ => { self.__buffa_unknown_fields - .push(::buffa::encoding::decode_unknown_field(tag, buf, depth)?); + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); } } ::core::result::Result::Ok(()) @@ -412,7 +412,7 @@ impl ::buffa::Message for FloatValue { &mut self, tag: ::buffa::encoding::Tag, buf: &mut impl ::buffa::bytes::Buf, - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result<(), ::buffa::DecodeError> { #[allow(unused_imports)] use ::buffa::bytes::Buf as _; @@ -431,7 +431,7 @@ impl ::buffa::Message for FloatValue { } _ => { self.__buffa_unknown_fields - .push(::buffa::encoding::decode_unknown_field(tag, buf, depth)?); + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); } } ::core::result::Result::Ok(()) @@ -654,7 +654,7 @@ impl ::buffa::Message for Int64Value { &mut self, tag: ::buffa::encoding::Tag, buf: &mut impl ::buffa::bytes::Buf, - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result<(), ::buffa::DecodeError> { #[allow(unused_imports)] use ::buffa::bytes::Buf as _; @@ -673,7 +673,7 @@ impl ::buffa::Message for Int64Value { } _ => { self.__buffa_unknown_fields - .push(::buffa::encoding::decode_unknown_field(tag, buf, depth)?); + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); } } ::core::result::Result::Ok(()) @@ -896,7 +896,7 @@ impl ::buffa::Message for UInt64Value { &mut self, tag: ::buffa::encoding::Tag, buf: &mut impl ::buffa::bytes::Buf, - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result<(), ::buffa::DecodeError> { #[allow(unused_imports)] use ::buffa::bytes::Buf as _; @@ -915,7 +915,7 @@ impl ::buffa::Message for UInt64Value { } _ => { self.__buffa_unknown_fields - .push(::buffa::encoding::decode_unknown_field(tag, buf, depth)?); + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); } } ::core::result::Result::Ok(()) @@ -1138,7 +1138,7 @@ impl ::buffa::Message for Int32Value { &mut self, tag: ::buffa::encoding::Tag, buf: &mut impl ::buffa::bytes::Buf, - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result<(), ::buffa::DecodeError> { #[allow(unused_imports)] use ::buffa::bytes::Buf as _; @@ -1157,7 +1157,7 @@ impl ::buffa::Message for Int32Value { } _ => { self.__buffa_unknown_fields - .push(::buffa::encoding::decode_unknown_field(tag, buf, depth)?); + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); } } ::core::result::Result::Ok(()) @@ -1380,7 +1380,7 @@ impl ::buffa::Message for UInt32Value { &mut self, tag: ::buffa::encoding::Tag, buf: &mut impl ::buffa::bytes::Buf, - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result<(), ::buffa::DecodeError> { #[allow(unused_imports)] use ::buffa::bytes::Buf as _; @@ -1399,7 +1399,7 @@ impl ::buffa::Message for UInt32Value { } _ => { self.__buffa_unknown_fields - .push(::buffa::encoding::decode_unknown_field(tag, buf, depth)?); + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); } } ::core::result::Result::Ok(()) @@ -1622,7 +1622,7 @@ impl ::buffa::Message for BoolValue { &mut self, tag: ::buffa::encoding::Tag, buf: &mut impl ::buffa::bytes::Buf, - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result<(), ::buffa::DecodeError> { #[allow(unused_imports)] use ::buffa::bytes::Buf as _; @@ -1641,7 +1641,7 @@ impl ::buffa::Message for BoolValue { } _ => { self.__buffa_unknown_fields - .push(::buffa::encoding::decode_unknown_field(tag, buf, depth)?); + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); } } ::core::result::Result::Ok(()) @@ -1867,7 +1867,7 @@ impl ::buffa::Message for StringValue { &mut self, tag: ::buffa::encoding::Tag, buf: &mut impl ::buffa::bytes::Buf, - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result<(), ::buffa::DecodeError> { #[allow(unused_imports)] use ::buffa::bytes::Buf as _; @@ -1886,7 +1886,7 @@ impl ::buffa::Message for StringValue { } _ => { self.__buffa_unknown_fields - .push(::buffa::encoding::decode_unknown_field(tag, buf, depth)?); + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); } } ::core::result::Result::Ok(()) @@ -2112,7 +2112,7 @@ impl ::buffa::Message for BytesValue { &mut self, tag: ::buffa::encoding::Tag, buf: &mut impl ::buffa::bytes::Buf, - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result<(), ::buffa::DecodeError> { #[allow(unused_imports)] use ::buffa::bytes::Buf as _; @@ -2131,7 +2131,7 @@ impl ::buffa::Message for BytesValue { } _ => { self.__buffa_unknown_fields - .push(::buffa::encoding::decode_unknown_field(tag, buf, depth)?); + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); } } ::core::result::Result::Ok(()) diff --git a/buffa-types/src/timestamp_ext.rs b/buffa-types/src/timestamp_ext.rs index df5464a4..eb82a9ec 100644 --- a/buffa-types/src/timestamp_ext.rs +++ b/buffa-types/src/timestamp_ext.rs @@ -418,7 +418,7 @@ mod tests { assert_eq!(view.seconds, ts.seconds); assert_eq!(view.nanos, ts.nanos); - let owned = view.to_owned_message(); + let owned = view.to_owned_message().unwrap(); assert_eq!(owned, ts); } diff --git a/buffa-types/src/view_serde_ext.rs b/buffa-types/src/view_serde_ext.rs index 8deb3eef..fb2c7d12 100644 --- a/buffa-types/src/view_serde_ext.rs +++ b/buffa-types/src/view_serde_ext.rs @@ -44,7 +44,9 @@ macro_rules! wkt_view_serialize { /// its proto3-JSON `Serialize` impl. Allocates the owned form /// for this field only; the parent message stays zero-copy. fn serialize(&self, s: S) -> Result { - self.to_owned_message().serialize(s) + self.to_owned_message() + .map_err(serde::ser::Error::custom)? + .serialize(s) } } )+ diff --git a/buffa-types/tests/decode_unknown_field_limit.rs b/buffa-types/tests/decode_unknown_field_limit.rs new file mode 100644 index 00000000..cdeba8a4 --- /dev/null +++ b/buffa-types/tests/decode_unknown_field_limit.rs @@ -0,0 +1,230 @@ +//! Regression tests for the unknown-field decode limit. +//! +//! Unknown wire data can occupy far more memory decoded than encoded — a +//! 2-byte varint field inflates to a ~40-byte `UnknownField`, so a 64 MiB +//! payload of minimal unknown fields used to force >1 GiB of heap. These +//! tests use `google.protobuf.Empty` as the receiving type (it has no +//! declared fields, so every payload byte routes through the unknown-field +//! path) and assert that the field-count limit bounds decoder memory +//! amplification independent of input size. + +use buffa::{DecodeError, DecodeOptions, Message, DEFAULT_UNKNOWN_FIELD_LIMIT}; +use buffa_types::Empty; + +/// `n` minimal (2-byte) varint unknown fields: tag 0x08 (field 1, varint), +/// value 0. +fn flat_varint_flood(n: usize) -> Vec { + let mut payload = Vec::with_capacity(2 * n); + for _ in 0..n { + payload.extend_from_slice(&[0x08, 0x00]); + } + payload +} + +/// The reported group-amplification payload: one unknown group (field 1) +/// holding `n` minimal varint fields. +fn group_amp(n: usize) -> Vec { + let mut payload = Vec::with_capacity(2 * n + 2); + payload.push(0x0b); // StartGroup, field 1 + for _ in 0..n { + payload.extend_from_slice(&[0x08, 0x00]); + } + payload.push(0x0c); // EndGroup, field 1 + payload +} + +/// More fields than the default limit, while the wire payload stays small +/// (~2 MiB). +const OVER_DEFAULT_LIMIT: usize = DEFAULT_UNKNOWN_FIELD_LIMIT + 1; + +#[test] +fn group_amplification_rejected_by_default_limit() { + let payload = group_amp(OVER_DEFAULT_LIMIT); + assert_eq!( + Empty::decode_from_slice(&payload), + Err(DecodeError::UnknownFieldLimitExceeded) + ); +} + +#[test] +fn flat_varint_flood_rejected_by_default_limit() { + // The report demonstrates the group vector, but a flat run of top-level + // unknown varints amplifies identically — the limit must catch both. + let payload = flat_varint_flood(OVER_DEFAULT_LIMIT); + assert_eq!( + Empty::decode_from_slice(&payload), + Err(DecodeError::UnknownFieldLimitExceeded) + ); +} + +#[test] +fn small_unknown_payloads_still_decode() { + // Forward-compatibility must keep working: a modest unknown payload + // decodes and round-trips under the default limit. + let payload = group_amp(100); + let msg = Empty::decode_from_slice(&payload).expect("within limit"); + assert_eq!(msg.encode_to_vec(), payload); +} + +#[test] +fn lowered_limit_rejects_what_default_accepts() { + let payload = flat_varint_flood(100); + Empty::decode_from_slice(&payload).expect("default limit accepts"); + assert_eq!( + DecodeOptions::new() + .with_unknown_field_limit(99) + .decode_from_slice::(&payload), + Err(DecodeError::UnknownFieldLimitExceeded) + ); +} + +#[test] +fn raised_limit_accepts_what_default_rejects() { + let payload = group_amp(OVER_DEFAULT_LIMIT); + let msg = DecodeOptions::new() + .with_unknown_field_limit(2 * DEFAULT_UNKNOWN_FIELD_LIMIT) + .decode_from_slice::(&payload) + .expect("raised limit accepts"); + assert_eq!(msg.encode_to_vec(), payload); +} + +#[test] +fn limit_is_exact() { + // The group field itself plus its nested fields each consume one slot, + // so a group of N fields needs exactly N + 1 slots. + let payload = group_amp(100); + DecodeOptions::new() + .with_unknown_field_limit(101) + .decode_from_slice::(&payload) + .expect("exactly enough slots"); + assert_eq!( + DecodeOptions::new() + .with_unknown_field_limit(100) + .decode_from_slice::(&payload), + Err(DecodeError::UnknownFieldLimitExceeded) + ); +} + +#[test] +fn length_delimited_payload_not_counted_against_limit() { + // One unknown LengthDelimited field with an 8 KiB payload consumes one + // slot regardless of payload size — the payload bytes are bounded by + // the input (and `with_max_message_size`), not by the field limit. + let inner_len = 8 * 1024; + let mut payload = vec![0x0a, 0x80, 0x40]; // tag (field 1, LD) + varint 8192 + payload.extend_from_slice(&vec![0u8; inner_len]); + let msg = DecodeOptions::new() + .with_unknown_field_limit(1) + .decode_from_slice::(&payload) + .expect("one slot suffices for one field"); + assert_eq!(msg.encode_to_vec(), payload); +} + +#[test] +fn limit_spans_nested_groups() { + // Splitting the flood across two sibling groups must not reset the + // limit: two groups of N/2 cost the same as one group of N (plus the + // two group fields themselves). + let n = OVER_DEFAULT_LIMIT / 2; + let mut payload = Vec::with_capacity(2 * OVER_DEFAULT_LIMIT + 4); + for _ in 0..2 { + payload.push(0x0b); + for _ in 0..n { + payload.extend_from_slice(&[0x08, 0x00]); + } + payload.push(0x0c); + } + assert_eq!( + Empty::decode_from_slice(&payload), + Err(DecodeError::UnknownFieldLimitExceeded) + ); +} + +// ── Zero-copy view path ──────────────────────────────────────────────────── +// +// Views store unknown fields as borrowed spans rather than decoded values, +// and adjacent unknown records coalesce into a single span — so a contiguous +// flood costs one slot regardless of field count, while interleaved runs +// are counted per span against the same unknown-field limit. + +mod view_path { + use super::*; + use buffa::view::MessageView; + use buffa_types::google::protobuf::__buffa::view::{DurationView, EmptyView}; + + #[test] + fn contiguous_unknown_flood_coalesces_to_one_span() { + // 100k unknown varint fields, fully contiguous: one span, one slot. + let payload = flat_varint_flood(100_000); + let view: EmptyView = DecodeOptions::new() + .with_unknown_field_limit(1) + .decode_view(&payload) + .expect("a contiguous flood coalesces into a single span"); + // Converting to owned materializes one UnknownField per record, so + // the decode-time allowance (1) carries through and is enforced. + assert_eq!( + view.to_owned_message(), + Err(DecodeError::UnknownFieldLimitExceeded) + ); + // With an adequate allowance the round-trip is byte-identical. + let view: EmptyView = EmptyView::decode_view(&payload).expect("default limit"); + let owned = view.to_owned_message().expect("within default allowance"); + assert_eq!(owned.encode_to_vec(), payload); + } + + #[test] + fn interleaved_unknown_runs_counted_against_limit() { + // Alternate a known Duration field (seconds = field 1) with an + // unknown field (field 99): every unknown run needs its own span. + let mut payload = Vec::new(); + for _ in 0..10 { + payload.extend_from_slice(&[0x08, 0x01]); // seconds = 1 (known) + payload.extend_from_slice(&[0x98, 0x06, 0x00]); // field 99 varint (unknown) + } + let view = DecodeOptions::new() + .with_unknown_field_limit(10) + .decode_view::(&payload) + .expect("10 spans fit a limit of 10"); + view.to_owned_message() + .expect("10 fields fit the same allowance"); + assert!(matches!( + DecodeOptions::new() + .with_unknown_field_limit(9) + .decode_view::(&payload), + Err(DecodeError::UnknownFieldLimitExceeded) + )); + } + + #[test] + fn coalesced_spans_convert_to_owned() { + // to_owned parses every record inside a coalesced span. + let payload = flat_varint_flood(50); + let view = EmptyView::decode_view(&payload).expect("decodes"); + let owned = view.to_owned_message().expect("within allowance"); + assert_eq!(owned.encode_to_vec(), payload); + } + + #[test] + fn group_flood_through_views_is_bounded() { + // The group payload through the view path: the group is skipped + // (not recursed into) and captured as one contiguous span. The + // decode-time allowance carries into conversion, where each nested + // record materializes as an owned field. + let payload = group_amp(100_000); + let view: EmptyView = DecodeOptions::new() + .with_unknown_field_limit(1) + .decode_view(&payload) + .expect("one span for the whole group record"); + assert_eq!( + view.to_owned_message(), + Err(DecodeError::UnknownFieldLimitExceeded) + ); + let view: EmptyView = EmptyView::decode_view(&payload).expect("default limit"); + assert_eq!( + view.to_owned_message() + .expect("default allowance") + .encode_to_vec(), + payload + ); + } +} diff --git a/buffa-types/tests/wkt_roundtrip.rs b/buffa-types/tests/wkt_roundtrip.rs index 95c37371..83ad53d8 100644 --- a/buffa-types/tests/wkt_roundtrip.rs +++ b/buffa-types/tests/wkt_roundtrip.rs @@ -224,6 +224,7 @@ fn view_roundtrip<'a, V: MessageView<'a>>(bytes: &'a [u8]) -> V::Owned { V::decode_view(bytes) .expect("decode_view") .to_owned_message() + .expect("to_owned_message") } #[test] diff --git a/buffa/src/encoding.rs b/buffa/src/encoding.rs index 90c50e5f..349363f5 100644 --- a/buffa/src/encoding.rs +++ b/buffa/src/encoding.rs @@ -379,12 +379,15 @@ pub fn skip_field(tag: Tag, buf: &mut impl Buf) -> Result<(), DecodeError> { /// Skip a field's payload, with an explicit recursion depth budget for groups. /// -/// Generated code must call this (not [`skip_field`]) when a `depth` parameter -/// is in scope, to prevent unknown group fields from resetting the recursion -/// budget and allowing depth-doubling attacks. +/// Generated code must call this (not [`skip_field`]) when a decode context +/// is in scope (passing `ctx.depth()`), to prevent unknown group fields from +/// resetting the recursion budget and allowing depth-doubling attacks. /// /// `depth` is the remaining nesting budget. For group fields this function /// calls itself recursively, decrementing `depth` by one each level. +/// Unlike [`decode_unknown_field`], skipping materializes nothing, so this +/// function deliberately takes only the depth — it never consumes the +/// unknown-field allowance. /// /// # Errors /// @@ -448,31 +451,43 @@ pub fn skip_field_depth(tag: Tag, buf: &mut impl Buf, depth: u32) -> Result<(), /// payload that follows it on the wire. Groups are decoded recursively until /// their matching `EndGroup` tag. /// -/// `depth` is the remaining nesting budget. For group fields this function -/// calls itself recursively, decrementing `depth` by one each time. When it -/// reaches zero [`DecodeError::RecursionLimitExceeded`] is returned. Pass -/// [`crate::message::RECURSION_LIMIT`] at the outermost call site; generated -/// code passes the `depth` value received by the enclosing `merge`. +/// `ctx` carries the remaining nesting depth and the shared unknown-field +/// allowance. For group fields this function calls itself recursively, +/// consuming one depth level each time. When the depth reaches zero +/// [`DecodeError::RecursionLimitExceeded`] is returned. Construct a fresh +/// [`DecodeContext`](crate::DecodeContext) at the outermost call site; +/// generated code passes the `ctx` value received by the enclosing `merge`. /// /// # Errors /// /// Returns an error if the buffer is truncated, the wire type is /// `EndGroup` (which indicates a structural mismatch in the wire data), -/// or the recursion limit is exceeded. +/// the recursion limit is exceeded, or the unknown-field limit is +/// exceeded. /// /// # Allocation /// -/// Length-delimited unknown fields allocate `vec![0u8; len]` where `len` -/// comes from wire data. The `buf.remaining() < len` check prevents -/// reading past the buffer, but callers processing untrusted input should -/// limit the input buffer size to bound maximum allocation. +/// Unknown fields can occupy far more memory decoded than encoded: a +/// 2-byte varint field becomes a ~40-byte +/// [`UnknownField`](crate::UnknownField), so an input-size cap alone does +/// **not** bound decoder memory. Every decoded field consumes one slot of +/// the context's shared unknown-field allowance **before** it is +/// materialized; when the allowance is exhausted decoding fails with +/// [`DecodeError::UnknownFieldLimitExceeded`]. Length-delimited payload +/// bytes are bounded by the input itself (the `buf.remaining() < len` +/// check forces the sender to actually deliver them), so they are not +/// counted against the limit — cap the input size to bound them. pub fn decode_unknown_field( tag: Tag, buf: &mut impl Buf, - depth: u32, + ctx: crate::DecodeContext<'_>, ) -> Result { use crate::unknown_fields::{UnknownField, UnknownFieldData, UnknownFields}; + // Every decoded field occupies one `UnknownField` slot in its parent's + // vector — consume an allowance slot up front so runs of tiny fields + // (2 wire bytes each) cannot amplify into unbounded heap growth. + ctx.register_unknown_field()?; let data = match tag.wire_type() { WireType::Varint => UnknownFieldData::Varint(decode_varint(buf)?), WireType::Fixed64 => { @@ -498,9 +513,7 @@ pub fn decode_unknown_field( UnknownFieldData::LengthDelimited(data) } WireType::StartGroup => { - let depth = depth - .checked_sub(1) - .ok_or(DecodeError::RecursionLimitExceeded)?; + let ctx = ctx.descend()?; let group_field_number = tag.field_number(); // Read nested fields until the matching EndGroup tag. let mut nested = UnknownFields::new(); @@ -514,7 +527,7 @@ pub fn decode_unknown_field( } break; } - nested.push(decode_unknown_field(nested_tag, buf, depth)?); + nested.push(decode_unknown_field(nested_tag, buf, ctx)?); } UnknownFieldData::Group(nested) } @@ -787,7 +800,7 @@ mod tests { // depth = 1: checked_sub(1) = 0, which is the floor but still Ok. let payload = encode_group_payload(1, &[]); let tag = Tag::new(1, WireType::StartGroup); - let result = decode_unknown_field(tag, &mut payload.as_slice(), 1); + let result = decode_unknown_field(tag, &mut payload.as_slice(), crate::test_ctx(1)); assert!(result.is_ok()); } @@ -797,11 +810,112 @@ mod tests { let payload = encode_group_payload(1, &[]); let tag = Tag::new(1, WireType::StartGroup); assert_eq!( - decode_unknown_field(tag, &mut payload.as_slice(), 0), + decode_unknown_field(tag, &mut payload.as_slice(), crate::test_ctx(0)), Err(DecodeError::RecursionLimitExceeded) ); } + // ---- decode_unknown_field: unknown-field limit ------------------------- + + /// Group-amplification payload: the body of a group containing `n` + /// minimal (2-byte) varint fields. Each inflates to a ~40-byte + /// `UnknownField`, so wire size amplifies ~20× in memory. + fn group_amp_body(n: usize) -> Vec { + let mut inner = Vec::with_capacity(2 * n); + for _ in 0..n { + inner.push(0x08); // field 1, Varint + inner.push(0x00); // value 0 + } + encode_group_payload(1, &inner) + } + + #[test] + fn test_group_amplification_exhausts_limit() { + // 1000 nested 2-byte varints, but only 100 unknown-field slots: + // the decoder must refuse long before materializing them all. + let payload = group_amp_body(1000); + let limit = core::cell::Cell::new(100); + let ctx = crate::DecodeContext::new(crate::RECURSION_LIMIT, &limit); + let tag = Tag::new(1, WireType::StartGroup); + assert_eq!( + decode_unknown_field(tag, &mut payload.as_slice(), ctx), + Err(DecodeError::UnknownFieldLimitExceeded) + ); + } + + #[test] + fn test_group_amplification_within_limit_succeeds() { + // The same payload decodes fine when the limit covers it. + let payload = group_amp_body(1000); + let limit = core::cell::Cell::new(crate::DEFAULT_UNKNOWN_FIELD_LIMIT); + let ctx = crate::DecodeContext::new(crate::RECURSION_LIMIT, &limit); + let tag = Tag::new(1, WireType::StartGroup); + let field = decode_unknown_field(tag, &mut payload.as_slice(), ctx).unwrap(); + let crate::unknown_fields::UnknownFieldData::Group(nested) = field.data else { + panic!("expected group"); + }; + assert_eq!(nested.iter().count(), 1000); + // The allowance recorded all 1001 UnknownField slots (1000 nested + + // the group itself). + assert_eq!( + limit.get(), + crate::DEFAULT_UNKNOWN_FIELD_LIMIT - 1001, + "every decoded field must consume one slot" + ); + } + + #[test] + fn test_limit_shared_across_sibling_fields() { + // Two sibling unknown fields decoded under one context draw from the + // same allowance: one slot admits the first field but not the second. + let limit = core::cell::Cell::new(1); + let ctx = crate::DecodeContext::new(crate::RECURSION_LIMIT, &limit); + let tag = Tag::new(1, WireType::Varint); + let mut payload: &[u8] = &[0x00]; + decode_unknown_field(tag, &mut payload, ctx).expect("first field fits"); + let mut payload: &[u8] = &[0x00]; + assert_eq!( + decode_unknown_field(tag, &mut payload, ctx), + Err(DecodeError::UnknownFieldLimitExceeded) + ); + } + + #[test] + fn test_length_delimited_payload_counts_as_one_field() { + // A large length-delimited payload consumes exactly one slot — its + // bytes are bounded by the input, not by the field limit. + let mut payload = Vec::new(); + encode_varint(4096, &mut payload); + payload.extend_from_slice(&[0u8; 4096]); + let limit = core::cell::Cell::new(1); + let ctx = crate::DecodeContext::new(crate::RECURSION_LIMIT, &limit); + let tag = Tag::new(1, WireType::LengthDelimited); + decode_unknown_field(tag, &mut payload.as_slice(), ctx).expect("one slot suffices"); + assert_eq!(limit.get(), 0); + // With no slots left, even a minimal field is refused. + let mut tiny: &[u8] = &[0x00]; + assert_eq!( + decode_unknown_field(Tag::new(1, WireType::Varint), &mut tiny, ctx), + Err(DecodeError::UnknownFieldLimitExceeded) + ); + } + + #[test] + fn test_length_delimited_truncated_still_reports_eof() { + // A truncated payload reports UnexpectedEof: the declared length is + // never allocated unless the sender actually delivers the bytes. + let mut payload = Vec::new(); + encode_varint(4096, &mut payload); + payload.extend_from_slice(&[0u8; 16]); // 16 of 4096 bytes + let limit = core::cell::Cell::new(crate::DEFAULT_UNKNOWN_FIELD_LIMIT); + let ctx = crate::DecodeContext::new(crate::RECURSION_LIMIT, &limit); + let tag = Tag::new(1, WireType::LengthDelimited); + assert_eq!( + decode_unknown_field(tag, &mut payload.as_slice(), ctx), + Err(DecodeError::UnexpectedEof) + ); + } + #[test] fn test_decode_unknown_field_end_group_mismatched_field_number() { // Group opened as field 1 but closed with field 2's EndGroup tag. @@ -809,7 +923,7 @@ mod tests { Tag::new(2, WireType::EndGroup).encode(&mut payload); // wrong field number let tag = Tag::new(1, WireType::StartGroup); assert_eq!( - decode_unknown_field(tag, &mut payload.as_slice(), 1), + decode_unknown_field(tag, &mut payload.as_slice(), crate::test_ctx(1)), Err(DecodeError::InvalidEndGroup(2)) ); } @@ -884,7 +998,7 @@ mod tests { let got = decode_unknown_field( case.tag, &mut case.payload.as_slice(), - crate::RECURSION_LIMIT, + crate::test_ctx(crate::RECURSION_LIMIT), ) .unwrap_or_else(|e| panic!("decode failed for tag {:?}: {e}", case.tag)); assert_eq!(got.number, case.tag.field_number()); @@ -906,7 +1020,11 @@ mod tests { ]; for &(tag, payload) in cases { assert_eq!( - decode_unknown_field(tag, &mut &payload[..], crate::RECURSION_LIMIT), + decode_unknown_field( + tag, + &mut &payload[..], + crate::test_ctx(crate::RECURSION_LIMIT) + ), Err(DecodeError::UnexpectedEof), "tag {tag:?}" ); @@ -918,7 +1036,7 @@ mod tests { // EndGroup as a top-level tag is invalid (only valid inside a group). let tag = Tag::new(1, WireType::EndGroup); assert_eq!( - decode_unknown_field(tag, &mut &[][..], crate::RECURSION_LIMIT), + decode_unknown_field(tag, &mut &[][..], crate::test_ctx(crate::RECURSION_LIMIT)), Err(DecodeError::InvalidWireType(4)) ); } @@ -961,7 +1079,10 @@ mod tests { let mut cur = buf.as_slice(); while !cur.is_empty() { let tag = Tag::decode(&mut cur).unwrap(); - decoded.push(decode_unknown_field(tag, &mut cur, crate::RECURSION_LIMIT).unwrap()); + decoded.push( + decode_unknown_field(tag, &mut cur, crate::test_ctx(crate::RECURSION_LIMIT)) + .unwrap(), + ); } assert_eq!(decoded, original); } @@ -1108,7 +1229,7 @@ mod tests { let tag = Tag::new(1, WireType::LengthDelimited); let mut buf: &[u8] = OVERSIZED_VARINT; assert_eq!( - decode_unknown_field(tag, &mut buf, crate::RECURSION_LIMIT), + decode_unknown_field(tag, &mut buf, crate::test_ctx(crate::RECURSION_LIMIT)), Err(DecodeError::MessageTooLarge) ); } diff --git a/buffa/src/error.rs b/buffa/src/error.rs index 887d2191..7e63af89 100644 --- a/buffa/src/error.rs +++ b/buffa/src/error.rs @@ -60,6 +60,21 @@ pub enum DecodeError { /// `option message_set_wire_format = true`. #[error("invalid MessageSet item: {0}")] InvalidMessageSet(&'static str), + + /// Decoding encountered more unknown fields than the configured limit. + /// + /// Unknown fields can be far smaller on the wire than in memory (a + /// 2-byte varint field occupies ~40 bytes as an + /// [`UnknownField`](crate::UnknownField)), so the decoder bounds how + /// many it will materialize rather than trusting the input size. By + /// default the limit is + /// [`DEFAULT_UNKNOWN_FIELD_LIMIT`](crate::DEFAULT_UNKNOWN_FIELD_LIMIT) + /// (1,000,000 fields per decode); use + /// [`DecodeOptions::with_unknown_field_limit`](crate::DecodeOptions::with_unknown_field_limit) + /// to raise it for trusted inputs that legitimately carry very many + /// unknown fields. + #[error("unknown field limit exceeded")] + UnknownFieldLimitExceeded, } /// An error that occurred while encoding a protobuf message. diff --git a/buffa/src/extension.rs b/buffa/src/extension.rs index f914dfc8..104e3c0b 100644 --- a/buffa/src/extension.rs +++ b/buffa/src/extension.rs @@ -1471,7 +1471,7 @@ mod tests { &mut self, tag: crate::encoding::Tag, buf: &mut impl bytes::Buf, - _depth: u32, + _ctx: crate::DecodeContext<'_>, ) -> Result<(), crate::DecodeError> { match tag.field_number() { 1 => self.a = crate::types::decode_int32(buf)?, diff --git a/buffa/src/lib.rs b/buffa/src/lib.rs index fe7e4637..5cf825bd 100644 --- a/buffa/src/lib.rs +++ b/buffa/src/lib.rs @@ -37,17 +37,20 @@ //! # fn example(bytes: &[u8]) -> Result<(), buffa::DecodeError> { //! let msg: Person = DecodeOptions::new() //! .with_recursion_limit(50) -//! .with_max_message_size(1024 * 1024) // 1 MiB +//! .with_max_message_size(1024 * 1024) // 1 MiB +//! .with_unknown_field_limit(10_000) // unknown fields per decode //! .decode_from_slice(&bytes)?; //! # Ok(()) //! # } //! ``` //! //! The trait-level convenience methods (`decode_from_slice`, `merge_from_slice`) -//! use a fixed recursion limit of [`RECURSION_LIMIT`] (100) and no explicit size -//! cap — a `&[u8]` is already bounded by whatever allocated it. Use `DecodeOptions` -//! when you want to reject oversized inputs at the decode entry point rather than -//! at the allocator. +//! use a fixed recursion limit of [`RECURSION_LIMIT`] (100), a fixed +//! [`DEFAULT_UNKNOWN_FIELD_LIMIT`] (1,000,000) bounding how many unknown +//! fields the decoder will materialize, and no explicit size cap — a +//! `&[u8]` is already bounded by whatever allocated it. Use `DecodeOptions` +//! to tune these, e.g. to reject oversized inputs at the decode entry point +//! rather than at the allocator. //! //! # Zero-copy views //! @@ -206,6 +209,17 @@ macro_rules! include_proto_relative { }; } +/// Test helper: a [`DecodeContext`] at `depth` with a fresh default-size +/// unknown-field allowance. Leaks the limit cell (tests only) so the +/// context can be passed around without scope gymnastics. +#[cfg(test)] +pub(crate) fn test_ctx(depth: u32) -> DecodeContext<'static> { + let limit = alloc::boxed::Box::leak(alloc::boxed::Box::new(core::cell::Cell::new( + DEFAULT_UNKNOWN_FIELD_LIMIT, + ))); + DecodeContext::new(depth, limit) +} + #[cfg(feature = "json")] pub mod any_registry; pub mod editions; @@ -239,7 +253,10 @@ pub mod view; pub use enumeration::{EnumValue, Enumeration}; pub use error::{DecodeError, EncodeError}; pub use extension::{Extension, ExtensionCodec, ExtensionSet}; -pub use message::{DecodeOptions, Message, MessageName, RECURSION_LIMIT}; +pub use message::{ + DecodeContext, DecodeOptions, Message, MessageName, DEFAULT_UNKNOWN_FIELD_LIMIT, + RECURSION_LIMIT, +}; pub use message_field::{DefaultInstance, MessageField}; pub use oneof::Oneof; pub use size_cache::SizeCache; @@ -489,7 +506,7 @@ pub mod __doctest_fixtures { &mut self, tag: crate::encoding::Tag, buf: &mut impl bytes::Buf, - _depth: u32, + _ctx: DecodeContext<'_>, ) -> Result<(), DecodeError> { crate::encoding::skip_field(tag, buf) } @@ -510,11 +527,11 @@ pub mod __doctest_fixtures { // Stub: examples are `no_run`, so this never executes. Ok(PersonView::default()) } - fn to_owned_message(&self) -> Person { - Person { + fn to_owned_message(&self) -> Result { + Ok(Person { name: self.name.into(), id: self.id, - } + }) } } diff --git a/buffa/src/message.rs b/buffa/src/message.rs index fccfeb2f..7c5ff1da 100644 --- a/buffa/src/message.rs +++ b/buffa/src/message.rs @@ -18,12 +18,123 @@ use crate::message_field::DefaultInstance; /// This value (100) matches the limit used by the official protobuf /// implementations and the protobuf conformance suite. /// -/// Pass this constant as the `depth` argument when calling [`Message::merge`] -/// at a top-level decode site. The provided convenience methods ([`Message::decode`], -/// [`Message::decode_from_slice`], [`Message::merge_from_slice`]) use this -/// limit automatically. +/// Pass this constant as the depth when constructing a [`DecodeContext`] for +/// a top-level [`Message::merge`] call. The provided convenience methods +/// ([`Message::decode`], [`Message::decode_from_slice`], +/// [`Message::merge_from_slice`]) use this limit automatically. pub const RECURSION_LIMIT: u32 = 100; +/// Default limit on unknown fields decoded per top-level decode: 1,000,000. +/// +/// Bounds the number of [`UnknownField`](crate::UnknownField) values the +/// decoder will materialize in a single top-level decode, independent of +/// the input size. Without this bound, wire data can force allocation far +/// in excess of its own size: every 2-byte unknown varint field +/// materialises a ~40-byte `UnknownField`, a ~20× amplification, so a +/// 64 MiB payload of unknown fields would otherwise force over 1 GiB of +/// heap. The count limit caps that overhead at roughly `limit × 40` bytes +/// (~40 MB at the default); unknown length-delimited *payload* bytes are +/// not counted against the limit because they are already bounded by the +/// input size, which [`DecodeOptions::with_max_message_size`] governs. +/// +/// A million unknown fields is far more than any realistic +/// forward-compatibility scenario needs. Raise the limit with +/// [`DecodeOptions::with_unknown_field_limit`] if you decode trusted +/// messages that legitimately carry more (e.g. a proxy forwarding messages +/// with a huge unpacked repeated field from a much newer schema). +pub const DEFAULT_UNKNOWN_FIELD_LIMIT: usize = 1_000_000; + +/// Per-decode limits threaded through every merge call. +/// +/// Carries the remaining recursion depth and a shared unknown-field +/// allowance. The context is `Copy` — passing it to a callee hands over the +/// current depth by value, while the unknown-field allowance lives in a +/// [`Cell`](core::cell::Cell) owned by the top-level decode entry point, so +/// every field decoded under one entry point draws from the same +/// allowance. +/// +/// Constructed automatically by the [`Message`] convenience methods +/// ([`decode`](Message::decode), [`decode_from_slice`](Message::decode_from_slice), +/// [`merge_from_slice`](Message::merge_from_slice)) and by [`DecodeOptions`]. +/// Construct one manually only when calling [`Message::merge`] or the other +/// depth-threading methods directly — and construct a **fresh limit cell +/// per top-level decode**. Reusing one cell across decode calls makes the +/// limit cumulative: each call drains it further until every decode fails +/// with [`DecodeError::UnknownFieldLimitExceeded`]. +/// +/// ```rust +/// # use buffa::__doctest_fixtures::Person; +/// use core::cell::Cell; +/// use buffa::{DecodeContext, Message, DEFAULT_UNKNOWN_FIELD_LIMIT, RECURSION_LIMIT}; +/// +/// # fn example(mut bytes: &[u8]) -> Result<(), buffa::DecodeError> { +/// let limit = Cell::new(DEFAULT_UNKNOWN_FIELD_LIMIT); +/// let mut msg = Person::default(); +/// msg.merge(&mut bytes, DecodeContext::new(RECURSION_LIMIT, &limit))?; +/// # Ok(()) +/// # } +/// ``` +#[derive(Clone, Copy, Debug)] +pub struct DecodeContext<'a> { + depth: u32, + unknown_fields_remaining: &'a core::cell::Cell, +} + +impl<'a> DecodeContext<'a> { + /// Create a context with `depth` remaining recursion levels and the + /// remaining unknown-field allowance stored in `unknown_field_limit`. + #[must_use] + pub fn new(depth: u32, unknown_field_limit: &'a core::cell::Cell) -> Self { + Self { + depth, + unknown_fields_remaining: unknown_field_limit, + } + } + + /// The remaining recursion depth. + #[must_use] + pub fn depth(&self) -> u32 { + self.depth + } + + /// The number of additional unknown fields this decode may materialize. + #[must_use] + pub fn remaining_unknown_fields(&self) -> usize { + self.unknown_fields_remaining.get() + } + + /// Consume one level of recursion depth. + /// + /// # Errors + /// + /// Returns [`DecodeError::RecursionLimitExceeded`] when the depth budget + /// is exhausted. + pub fn descend(self) -> Result { + let depth = self + .depth + .checked_sub(1) + .ok_or(DecodeError::RecursionLimitExceeded)?; + Ok(Self { depth, ..self }) + } + + /// Consume one slot of the shared unknown-field allowance. + /// + /// Call **before** materializing an [`UnknownField`](crate::UnknownField). + /// + /// # Errors + /// + /// Returns [`DecodeError::UnknownFieldLimitExceeded`] (leaving the + /// allowance unchanged) when no slots remain. + pub fn register_unknown_field(&self) -> Result<(), DecodeError> { + let remaining = self.unknown_fields_remaining.get(); + if remaining == 0 { + return Err(DecodeError::UnknownFieldLimitExceeded); + } + self.unknown_fields_remaining.set(remaining - 1); + Ok(()) + } +} + /// The core trait implemented by all protobuf message types. /// /// This trait is implemented by **generated code** — you write a `.proto` file, @@ -171,8 +282,9 @@ pub trait Message: DefaultInstance + Clone + PartialEq + Send + Sync { where Self: Sized, { + let limit = core::cell::Cell::new(DEFAULT_UNKNOWN_FIELD_LIMIT); let mut msg = Self::default(); - msg.merge(buf, RECURSION_LIMIT)?; + msg.merge(buf, DecodeContext::new(RECURSION_LIMIT, &limit))?; Ok(msg) } @@ -224,8 +336,13 @@ pub trait Message: DefaultInstance + Clone + PartialEq + Send + Sync { // through every recursion level, avoiding E0275 for recursive // message types like `google.protobuf.Struct ↔ Value`. let limit = buf.remaining() - len; + let field_limit = core::cell::Cell::new(DEFAULT_UNKNOWN_FIELD_LIMIT); let mut msg = Self::default(); - msg.merge_to_limit(buf, RECURSION_LIMIT, limit)?; + msg.merge_to_limit( + buf, + DecodeContext::new(RECURSION_LIMIT, &field_limit), + limit, + )?; if buf.remaining() != limit { let remaining = buf.remaining(); if remaining > limit { @@ -244,19 +361,21 @@ pub trait Message: DefaultInstance + Clone + PartialEq + Send + Sync { /// Both [`merge_to_limit`](Self::merge_to_limit) and /// [`merge_group`](Self::merge_group) call this in their respective loops. /// - /// `depth` is the remaining nesting budget. + /// `ctx` carries the remaining nesting depth and the shared allocation + /// budget. /// /// # Errors /// /// Returns a [`DecodeError`] if: /// - the buffer is truncated or malformed, - /// - a wire-type mismatch is detected for a known field, or - /// - the recursion limit is exceeded. + /// - a wire-type mismatch is detected for a known field, + /// - the recursion limit is exceeded, or + /// - the allocation budget is exhausted. fn merge_field( &mut self, tag: crate::encoding::Tag, buf: &mut impl Buf, - depth: u32, + ctx: DecodeContext<'_>, ) -> Result<(), DecodeError>; /// Merge fields from a buffer until `buf.remaining()` reaches `limit`. @@ -271,19 +390,20 @@ pub trait Message: DefaultInstance + Clone + PartialEq + Send + Sync { /// [`merge_length_delimited`](Self::merge_length_delimited) uphold this /// invariant. /// - /// `depth` is the remaining nesting budget. Each call to - /// [`merge_length_delimited`](Self::merge_length_delimited) decrements it - /// by one before recursing; when it reaches zero the call returns - /// [`DecodeError::RecursionLimitExceeded`]. + /// `ctx` carries the remaining nesting depth and the shared allocation + /// budget. Each call to + /// [`merge_length_delimited`](Self::merge_length_delimited) consumes one + /// depth level before recursing; when the depth reaches zero the call + /// returns [`DecodeError::RecursionLimitExceeded`]. fn merge_to_limit( &mut self, buf: &mut impl Buf, - depth: u32, + ctx: DecodeContext<'_>, limit: usize, ) -> Result<(), DecodeError> { while buf.remaining() > limit { let tag = crate::encoding::Tag::decode(buf)?; - self.merge_field(tag, buf, depth)?; + self.merge_field(tag, buf, ctx)?; } Ok(()) } @@ -306,12 +426,10 @@ pub trait Message: DefaultInstance + Clone + PartialEq + Send + Sync { fn merge_group( &mut self, buf: &mut impl Buf, - depth: u32, + ctx: DecodeContext<'_>, field_number: u32, ) -> Result<(), DecodeError> { - let depth = depth - .checked_sub(1) - .ok_or(DecodeError::RecursionLimitExceeded)?; + let ctx = ctx.descend()?; loop { if !buf.has_remaining() { return Err(DecodeError::UnexpectedEof); @@ -324,7 +442,7 @@ pub trait Message: DefaultInstance + Clone + PartialEq + Send + Sync { Err(DecodeError::InvalidEndGroup(tag.field_number())) }; } - self.merge_field(tag, buf, depth)?; + self.merge_field(tag, buf, ctx)?; } } @@ -334,15 +452,17 @@ pub trait Message: DefaultInstance + Clone + PartialEq + Send + Sync { /// or appended for repeated fields, following standard protobuf merge /// semantics. /// - /// `depth` is the remaining nesting budget. Each call to - /// [`merge_length_delimited`](Self::merge_length_delimited) decrements it - /// by one before recursing; when it reaches zero the call returns - /// [`DecodeError::RecursionLimitExceeded`]. Pass [`RECURSION_LIMIT`] at - /// the outermost call site, or use the convenience methods - /// ([`decode`](Self::decode), [`merge_from_slice`](Self::merge_from_slice)) - /// which do this automatically. - fn merge(&mut self, buf: &mut impl Buf, depth: u32) -> Result<(), DecodeError> { - self.merge_to_limit(buf, depth, 0) + /// `ctx` carries the remaining nesting depth and the shared allocation + /// budget. Each call to + /// [`merge_length_delimited`](Self::merge_length_delimited) consumes one + /// depth level before recursing; when the depth reaches zero the call + /// returns [`DecodeError::RecursionLimitExceeded`]. Construct a fresh + /// [`DecodeContext`] at the outermost call site, or use the convenience + /// methods ([`decode`](Self::decode), + /// [`merge_from_slice`](Self::merge_from_slice)) which do this + /// automatically. + fn merge(&mut self, buf: &mut impl Buf, ctx: DecodeContext<'_>) -> Result<(), DecodeError> { + self.merge_to_limit(buf, ctx, 0) } /// Merge fields from a byte slice into this message. @@ -350,7 +470,8 @@ pub trait Message: DefaultInstance + Clone + PartialEq + Send + Sync { /// Convenience wrapper around [`merge`](Self::merge) that avoids the /// `&mut bytes.as_slice()` incantation. fn merge_from_slice(&mut self, mut data: &[u8]) -> Result<(), DecodeError> { - self.merge(&mut data, RECURSION_LIMIT) + let limit = core::cell::Cell::new(DEFAULT_UNKNOWN_FIELD_LIMIT); + self.merge(&mut data, DecodeContext::new(RECURSION_LIMIT, &limit)) } /// Merge fields from a length-delimited sub-message payload into this message. @@ -365,10 +486,12 @@ pub trait Message: DefaultInstance + Clone + PartialEq + Send + Sync { /// — the sub-message is merged into the existing value rather than /// replaced, per protobuf merge semantics. /// - /// `depth` is the remaining nesting budget passed down from the enclosing - /// [`merge_to_limit`](Self::merge_to_limit) call. This method decrements - /// it by one before calling the inner `merge_to_limit`; when it reaches - /// zero it returns [`DecodeError::RecursionLimitExceeded`]. + /// `ctx` carries the remaining nesting depth and the shared allocation + /// budget passed down from the enclosing + /// [`merge_to_limit`](Self::merge_to_limit) call. This method consumes + /// one depth level before calling the inner `merge_to_limit`; when the + /// depth reaches zero it returns + /// [`DecodeError::RecursionLimitExceeded`]. /// /// Enforces the same 2 GiB safety limit as [`decode_length_delimited`](Self::decode_length_delimited). /// @@ -380,11 +503,9 @@ pub trait Message: DefaultInstance + Clone + PartialEq + Send + Sync { fn merge_length_delimited( &mut self, buf: &mut impl Buf, - depth: u32, + ctx: DecodeContext<'_>, ) -> Result<(), DecodeError> { - let depth = depth - .checked_sub(1) - .ok_or(DecodeError::RecursionLimitExceeded)?; + let ctx = ctx.descend()?; const MAX_SUB_MESSAGE_BYTES: u64 = 0x7FFF_FFFF; let len_u64 = crate::encoding::decode_varint(buf)?; if len_u64 > MAX_SUB_MESSAGE_BYTES { @@ -400,7 +521,7 @@ pub trait Message: DefaultInstance + Clone + PartialEq + Send + Sync { // which would grow the type at each recursion level and trigger // E0275 for recursive message types like `Struct ↔ Value`. let limit = buf.remaining() - len; - self.merge_to_limit(buf, depth, limit)?; + self.merge_to_limit(buf, ctx, limit)?; if buf.remaining() != limit { let remaining = buf.remaining(); if remaining > limit { @@ -534,6 +655,7 @@ pub trait MessageName { pub struct DecodeOptions { recursion_limit: u32, max_message_size: usize, + unknown_field_limit: usize, } /// Default maximum message size: 2 GiB - 1 (matches the internal sub-message @@ -552,10 +674,12 @@ impl DecodeOptions { /// Defaults: /// - `recursion_limit`: 100 (same as [`RECURSION_LIMIT`]) /// - `max_message_size`: 2 GiB - 1 + /// - `unknown_field_limit`: 1,000,000 (same as [`DEFAULT_UNKNOWN_FIELD_LIMIT`]) pub fn new() -> Self { Self { recursion_limit: RECURSION_LIMIT, max_message_size: DEFAULT_MAX_MESSAGE_SIZE, + unknown_field_limit: DEFAULT_UNKNOWN_FIELD_LIMIT, } } @@ -588,11 +712,43 @@ impl DecodeOptions { self } + /// Set the maximum number of unknown fields decoded per decode call. + /// + /// Each decoded unknown field occupies a ~40-byte + /// [`UnknownField`](crate::UnknownField) slot regardless of its wire + /// size (a minimal field is 2 wire bytes — a ~20× amplification), so an + /// input-size cap alone does not bound decoder memory; this limit does, + /// at roughly `limit × 40` bytes of slot overhead. Unknown + /// length-delimited *payload* bytes are not counted — they are bounded + /// by the input size, which + /// [`with_max_message_size`](Self::with_max_message_size) governs. When + /// the limit is exceeded, decoding returns + /// [`DecodeError::UnknownFieldLimitExceeded`]. + /// + /// Zero-copy view decoding ([`decode_view`](Self::decode_view)) counts + /// **coalesced spans** — one per contiguous run of unknown fields, at + /// ~16 bytes each — rather than individual fields, so the same value is + /// more permissive for views (a single contiguous run of any length + /// costs one slot). Converting a view to an owned message re-materializes + /// unknown fields under the *default* limit, not this one. + /// + /// Default: 1,000,000 ([`DEFAULT_UNKNOWN_FIELD_LIMIT`]). + #[must_use] + pub fn with_unknown_field_limit(mut self, count: usize) -> Self { + self.unknown_field_limit = count; + self + } + /// Returns the configured recursion depth limit. pub fn recursion_limit(&self) -> u32 { self.recursion_limit } + /// Returns the configured unknown-field limit. + pub fn unknown_field_limit(&self) -> usize { + self.unknown_field_limit + } + /// Returns the configured maximum message size in bytes. pub fn max_message_size(&self) -> usize { self.max_message_size @@ -603,8 +759,9 @@ impl DecodeOptions { if buf.remaining() > self.max_message_size { return Err(DecodeError::MessageTooLarge); } + let limit = core::cell::Cell::new(self.unknown_field_limit); let mut msg = M::default(); - msg.merge(buf, self.recursion_limit)?; + msg.merge(buf, DecodeContext::new(self.recursion_limit, &limit))?; Ok(msg) } @@ -613,8 +770,12 @@ impl DecodeOptions { if data.len() > self.max_message_size { return Err(DecodeError::MessageTooLarge); } + let limit = core::cell::Cell::new(self.unknown_field_limit); let mut msg = M::default(); - msg.merge(&mut &*data, self.recursion_limit)?; + msg.merge( + &mut &*data, + DecodeContext::new(self.recursion_limit, &limit), + )?; Ok(msg) } @@ -639,8 +800,13 @@ impl DecodeOptions { return Err(DecodeError::UnexpectedEof); } let limit = buf.remaining() - len; + let field_limit = core::cell::Cell::new(self.unknown_field_limit); let mut msg = M::default(); - msg.merge_to_limit(buf, self.recursion_limit, limit)?; + msg.merge_to_limit( + buf, + DecodeContext::new(self.recursion_limit, &field_limit), + limit, + )?; if buf.remaining() != limit { let remaining = buf.remaining(); if remaining > limit { @@ -657,7 +823,8 @@ impl DecodeOptions { if buf.remaining() > self.max_message_size { return Err(DecodeError::MessageTooLarge); } - msg.merge(buf, self.recursion_limit) + let limit = core::cell::Cell::new(self.unknown_field_limit); + msg.merge(buf, DecodeContext::new(self.recursion_limit, &limit)) } /// Merge fields from a byte slice into an existing message. @@ -669,10 +836,25 @@ impl DecodeOptions { if data.len() > self.max_message_size { return Err(DecodeError::MessageTooLarge); } - msg.merge(&mut &*data, self.recursion_limit) + let limit = core::cell::Cell::new(self.unknown_field_limit); + msg.merge( + &mut &*data, + DecodeContext::new(self.recursion_limit, &limit), + ) } /// Decode a zero-copy view from a byte slice. + /// + /// Enforces `max_message_size` on the input, and passes the recursion + /// limit and unknown-field limit to the view decoder (views count + /// coalesced unknown-field spans against the limit — see + /// [`with_unknown_field_limit`](Self::with_unknown_field_limit)). + /// + /// # Errors + /// + /// Returns [`DecodeError::MessageTooLarge`] for oversized input, or any + /// error from the view decoder (malformed wire data, recursion limit, + /// unknown-field limit). pub fn decode_view<'a, V: crate::view::MessageView<'a>>( &self, buf: &'a [u8], @@ -680,7 +862,8 @@ impl DecodeOptions { if buf.len() > self.max_message_size { return Err(DecodeError::MessageTooLarge); } - V::decode_view_with_limit(buf, self.recursion_limit) + let limit = core::cell::Cell::new(self.unknown_field_limit); + V::decode_view_with_ctx(buf, DecodeContext::new(self.recursion_limit, &limit)) } /// Decode a message by reading all bytes from a [`std::io::Read`] source. @@ -844,7 +1027,7 @@ mod tests { &mut self, tag: crate::encoding::Tag, buf: &mut impl Buf, - _depth: u32, + _ctx: DecodeContext<'_>, ) -> Result<(), DecodeError> { match tag.field_number() { 1 => { @@ -872,8 +1055,11 @@ mod tests { fn test_merge_length_delimited_basic() { let src = FlatMsg { value: 42 }; let mut dst = FlatMsg::default(); - dst.merge_length_delimited(&mut wire_bytes(&src).as_slice(), RECURSION_LIMIT) - .unwrap(); + dst.merge_length_delimited( + &mut wire_bytes(&src).as_slice(), + crate::test_ctx(RECURSION_LIMIT), + ) + .unwrap(); assert_eq!(dst.value, 42); } @@ -883,13 +1069,13 @@ mod tests { let mut dst = FlatMsg::default(); dst.merge_length_delimited( &mut wire_bytes(&FlatMsg { value: 1 }).as_slice(), - RECURSION_LIMIT, + crate::test_ctx(RECURSION_LIMIT), ) .unwrap(); assert_eq!(dst.value, 1); dst.merge_length_delimited( &mut wire_bytes(&FlatMsg { value: 2 }).as_slice(), - RECURSION_LIMIT, + crate::test_ctx(RECURSION_LIMIT), ) .unwrap(); assert_eq!(dst.value, 2); @@ -903,7 +1089,7 @@ mod tests { buf.extend_from_slice(&[0x01, 0x01]); let mut dst = FlatMsg::default(); assert_eq!( - dst.merge_length_delimited(&mut buf.as_slice(), RECURSION_LIMIT), + dst.merge_length_delimited(&mut buf.as_slice(), crate::test_ctx(RECURSION_LIMIT)), Err(DecodeError::UnexpectedEof) ); } @@ -915,7 +1101,7 @@ mod tests { encode_varint(0x8000_0000u64, &mut buf); // 2 GiB + 1 let mut dst = FlatMsg::default(); assert_eq!( - dst.merge_length_delimited(&mut buf.as_slice(), RECURSION_LIMIT), + dst.merge_length_delimited(&mut buf.as_slice(), crate::test_ctx(RECURSION_LIMIT)), Err(DecodeError::MessageTooLarge) ); } @@ -930,11 +1116,11 @@ mod tests { let src = FlatMsg { value: 7 }; let mut dst = FlatMsg::default(); assert_eq!( - dst.merge_length_delimited(&mut wire_bytes(&src).as_slice(), 0), + dst.merge_length_delimited(&mut wire_bytes(&src).as_slice(), crate::test_ctx(0)), Err(DecodeError::RecursionLimitExceeded) ); // depth=1 succeeds: exactly one level is consumed. - dst.merge_length_delimited(&mut wire_bytes(&src).as_slice(), 1) + dst.merge_length_delimited(&mut wire_bytes(&src).as_slice(), crate::test_ctx(1)) .unwrap(); assert_eq!(dst.value, 7); } @@ -1093,15 +1279,18 @@ mod tests { let opts = DecodeOptions::new(); assert_eq!(opts.recursion_limit(), RECURSION_LIMIT); assert_eq!(opts.max_message_size(), 0x7FFF_FFFF); + assert_eq!(opts.unknown_field_limit(), DEFAULT_UNKNOWN_FIELD_LIMIT); } #[test] fn decode_options_getters_return_custom_values() { let opts = DecodeOptions::new() .with_recursion_limit(42) - .with_max_message_size(1024); + .with_max_message_size(1024) + .with_unknown_field_limit(2048); assert_eq!(opts.recursion_limit(), 42); assert_eq!(opts.max_message_size(), 1024); + assert_eq!(opts.unknown_field_limit(), 2048); } #[test] @@ -1110,6 +1299,7 @@ mod tests { let opts = DecodeOptions::default(); assert_eq!(opts.recursion_limit(), RECURSION_LIMIT); assert_eq!(opts.max_message_size(), 0x7FFF_FFFF); + assert_eq!(opts.unknown_field_limit(), DEFAULT_UNKNOWN_FIELD_LIMIT); } #[test] @@ -1224,7 +1414,7 @@ mod tests { fn test_merge_group_basic() { let data = group_bytes(42, 5); let mut dst = FlatMsg::default(); - dst.merge_group(&mut data.as_slice(), RECURSION_LIMIT, 5) + dst.merge_group(&mut data.as_slice(), crate::test_ctx(RECURSION_LIMIT), 5) .unwrap(); assert_eq!(dst.value, 42); } @@ -1234,7 +1424,7 @@ mod tests { // Group with no fields — just EndGroup. let data = group_bytes(0, 3); let mut dst = FlatMsg::default(); - dst.merge_group(&mut data.as_slice(), RECURSION_LIMIT, 3) + dst.merge_group(&mut data.as_slice(), crate::test_ctx(RECURSION_LIMIT), 3) .unwrap(); assert_eq!(dst.value, 0); } @@ -1244,10 +1434,10 @@ mod tests { let data1 = group_bytes(1, 5); let data2 = group_bytes(2, 5); let mut dst = FlatMsg::default(); - dst.merge_group(&mut data1.as_slice(), RECURSION_LIMIT, 5) + dst.merge_group(&mut data1.as_slice(), crate::test_ctx(RECURSION_LIMIT), 5) .unwrap(); assert_eq!(dst.value, 1); - dst.merge_group(&mut data2.as_slice(), RECURSION_LIMIT, 5) + dst.merge_group(&mut data2.as_slice(), crate::test_ctx(RECURSION_LIMIT), 5) .unwrap(); assert_eq!(dst.value, 2); } @@ -1259,7 +1449,7 @@ mod tests { let data = group_bytes(42, 5); let mut dst = FlatMsg::default(); assert_eq!( - dst.merge_group(&mut data.as_slice(), 0, 5), + dst.merge_group(&mut data.as_slice(), crate::test_ctx(0), 5), Err(DecodeError::RecursionLimitExceeded) ); } @@ -1270,7 +1460,8 @@ mod tests { // merge_field doesn't recurse further. let data = group_bytes(7, 5); let mut dst = FlatMsg::default(); - dst.merge_group(&mut data.as_slice(), 1, 5).unwrap(); + dst.merge_group(&mut data.as_slice(), crate::test_ctx(1), 5) + .unwrap(); assert_eq!(dst.value, 7); } @@ -1283,7 +1474,7 @@ mod tests { let mut dst = FlatMsg::default(); assert_eq!( - dst.merge_group(&mut data.as_slice(), RECURSION_LIMIT, 5), + dst.merge_group(&mut data.as_slice(), crate::test_ctx(RECURSION_LIMIT), 5), Err(DecodeError::InvalidEndGroup(99)) ); } @@ -1299,7 +1490,7 @@ mod tests { let mut dst = FlatMsg::default(); assert_eq!( - dst.merge_group(&mut data.as_slice(), RECURSION_LIMIT, 5), + dst.merge_group(&mut data.as_slice(), crate::test_ctx(RECURSION_LIMIT), 5), Err(DecodeError::UnexpectedEof) ); } @@ -1308,7 +1499,7 @@ mod tests { fn test_merge_group_empty_buffer() { let mut dst = FlatMsg::default(); assert_eq!( - dst.merge_group(&mut [].as_slice(), RECURSION_LIMIT, 5), + dst.merge_group(&mut [].as_slice(), crate::test_ctx(RECURSION_LIMIT), 5), Err(DecodeError::UnexpectedEof) ); } @@ -1330,7 +1521,7 @@ mod tests { Tag::new(5, WireType::EndGroup).encode(&mut data); let mut dst = FlatMsg::default(); - dst.merge_group(&mut data.as_slice(), RECURSION_LIMIT, 5) + dst.merge_group(&mut data.as_slice(), crate::test_ctx(RECURSION_LIMIT), 5) .unwrap(); assert_eq!(dst.value, 99); } @@ -1343,7 +1534,8 @@ mod tests { let mut cur = data.as_slice(); let mut dst = FlatMsg::default(); - dst.merge_group(&mut cur, RECURSION_LIMIT, 5).unwrap(); + dst.merge_group(&mut cur, crate::test_ctx(RECURSION_LIMIT), 5) + .unwrap(); assert_eq!(dst.value, 42); assert_eq!(cur, &[0xDE, 0xAD]); } diff --git a/buffa/src/message_set.rs b/buffa/src/message_set.rs index 7d975ba7..537498be 100644 --- a/buffa/src/message_set.rs +++ b/buffa/src/message_set.rs @@ -41,16 +41,27 @@ pub const MESSAGE_TAG: u64 = (3 << 3) | 2; /// Returns `(type_id, message_bytes)`. `message_bytes` is empty if no /// `message` field was present (valid: an empty sub-message). /// -/// `depth` is the remaining recursion budget for skipping unknown group fields -/// **inside** the Item group. The caller should pass `caller_depth - 1` (the -/// Item group itself consumes one level). +/// `ctx` carries the remaining recursion depth for skipping unknown group +/// fields **inside** the Item group, plus the shared unknown-field +/// allowance. The caller should pass `caller_ctx.descend()?` (the Item +/// group itself consumes one level). The item consumes one slot of the +/// unknown-field allowance — the caller stores it as one +/// [`UnknownField`](crate::UnknownField). /// /// # Errors /// /// Returns [`DecodeError::InvalidMessageSet`] if `type_id` is missing or out /// of the valid range `[1, i32::MAX]`. Returns other decode errors on -/// malformed input (truncated varint, buffer underrun, mismatched end-group). -pub fn merge_item(buf: &mut impl Buf, depth: u32) -> Result<(u32, Vec), DecodeError> { +/// malformed input (truncated varint, buffer underrun, mismatched end-group) +/// or when the unknown-field limit is exceeded. +pub fn merge_item( + buf: &mut impl Buf, + ctx: crate::DecodeContext<'_>, +) -> Result<(u32, Vec), DecodeError> { + // The caller stores the result as one UnknownField slot — consume an + // allowance slot here so MessageSet items draw from the same limit as + // regular unknowns. + ctx.register_unknown_field()?; let mut type_id: Option = None; let mut message: Vec = Vec::new(); @@ -90,9 +101,9 @@ pub fn merge_item(buf: &mut impl Buf, depth: u32) -> Result<(u32, Vec), Deco } _ => { // Unknown field inside the Item group: skip. Generated code - // passes `depth - 1` into `merge_item`, so nested groups here - // share the caller's recursion budget. - skip_field_depth(tag, buf, depth)?; + // passes `ctx.descend()?` into `merge_item`, so nested groups + // here share the caller's recursion budget. + skip_field_depth(tag, buf, ctx.depth())?; } } } @@ -117,6 +128,12 @@ pub const fn item_encoded_len(number: u32, payload_len: usize) -> usize { #[cfg(test)] mod tests { use super::*; + + /// Call `merge_item` with a fresh default-limit context at `depth`. + fn merge_item_d(buf: &mut impl Buf, depth: u32) -> Result<(u32, Vec), DecodeError> { + let limit = core::cell::Cell::new(crate::DEFAULT_UNKNOWN_FIELD_LIMIT); + merge_item(buf, crate::DecodeContext::new(depth, &limit)) + } use crate::encoding::encode_varint; /// Build a MessageSet Item group body (no SGROUP tag — `merge_item` @@ -162,7 +179,7 @@ mod tests { #[test] fn merge_item_type_id_then_message() { let body = item_body(&[&type_id_field(1000), &message_field(b"hello"), &end_group()]); - let (tid, msg) = merge_item(&mut body.as_slice(), 50).expect("merge"); + let (tid, msg) = merge_item_d(&mut body.as_slice(), 50).expect("merge"); assert_eq!(tid, 1000); assert_eq!(msg, b"hello"); } @@ -170,7 +187,7 @@ mod tests { #[test] fn merge_item_message_then_type_id() { let body = item_body(&[&message_field(b"world"), &type_id_field(42), &end_group()]); - let (tid, msg) = merge_item(&mut body.as_slice(), 50).expect("merge"); + let (tid, msg) = merge_item_d(&mut body.as_slice(), 50).expect("merge"); assert_eq!(tid, 42); assert_eq!(msg, b"world"); } @@ -188,7 +205,7 @@ mod tests { &message_field(b"ok"), &end_group(), ]); - let (tid, msg) = merge_item(&mut body.as_slice(), 50).expect("merge"); + let (tid, msg) = merge_item_d(&mut body.as_slice(), 50).expect("merge"); assert_eq!(tid, 7); assert_eq!(msg, b"ok"); } @@ -206,19 +223,19 @@ mod tests { let body = item_body(&[&type_id_field(5), &junk, &message_field(b"x"), &end_group()]); // With depth budget: succeeds. - let (tid, msg) = merge_item(&mut body.as_slice(), 10).expect("merge"); + let (tid, msg) = merge_item_d(&mut body.as_slice(), 10).expect("merge"); assert_eq!(tid, 5); assert_eq!(msg, b"x"); // With depth exhausted: fails. - let err = merge_item(&mut body.as_slice(), 0).unwrap_err(); + let err = merge_item_d(&mut body.as_slice(), 0).unwrap_err(); assert_eq!(err, DecodeError::RecursionLimitExceeded); } #[test] fn merge_item_missing_type_id_errors() { let body = item_body(&[&message_field(b"orphan"), &end_group()]); - let err = merge_item(&mut body.as_slice(), 50).unwrap_err(); + let err = merge_item_d(&mut body.as_slice(), 50).unwrap_err(); assert_eq!(err, DecodeError::InvalidMessageSet("missing type_id")); } @@ -226,7 +243,7 @@ mod tests { fn merge_item_missing_message_yields_empty() { // Missing `message` is valid — it's an empty sub-message. let body = item_body(&[&type_id_field(3), &end_group()]); - let (tid, msg) = merge_item(&mut body.as_slice(), 50).expect("merge"); + let (tid, msg) = merge_item_d(&mut body.as_slice(), 50).expect("merge"); assert_eq!(tid, 3); assert_eq!(msg, b""); } @@ -239,7 +256,7 @@ mod tests { &message_field(b"cd"), &end_group(), ]); - let (tid, msg) = merge_item(&mut body.as_slice(), 50).expect("merge"); + let (tid, msg) = merge_item_d(&mut body.as_slice(), 50).expect("merge"); assert_eq!(tid, 9); assert_eq!(msg, b"abcd"); } @@ -253,7 +270,7 @@ mod tests { &message_field(b"x"), &end_group(), ]); - let (tid, msg) = merge_item(&mut body.as_slice(), 50).expect("merge"); + let (tid, msg) = merge_item_d(&mut body.as_slice(), 50).expect("merge"); assert_eq!(tid, 99); assert_eq!(msg, b"x"); } @@ -269,7 +286,7 @@ mod tests { ]; for &(id, ok) in cases { let body = item_body(&[&type_id_field(id), &message_field(b""), &end_group()]); - let result = merge_item(&mut body.as_slice(), 50); + let result = merge_item_d(&mut body.as_slice(), 50); assert_eq!(result.is_ok(), ok, "type_id = {id}"); } } @@ -280,7 +297,7 @@ mod tests { let mut bad_end = Vec::new(); encode_varint((7 << 3) | 4, &mut bad_end); let body = item_body(&[&type_id_field(1), &bad_end]); - let err = merge_item(&mut body.as_slice(), 50).unwrap_err(); + let err = merge_item_d(&mut body.as_slice(), 50).unwrap_err(); assert_eq!(err, DecodeError::InvalidEndGroup(7)); } @@ -293,7 +310,7 @@ mod tests { encode_varint(MESSAGE_TAG, &mut body); encode_varint(100, &mut body); body.extend_from_slice(b"xy"); - let err = merge_item(&mut body.as_slice(), 50).unwrap_err(); + let err = merge_item_d(&mut body.as_slice(), 50).unwrap_err(); assert_eq!(err, DecodeError::UnexpectedEof); } diff --git a/buffa/src/text/decoder.rs b/buffa/src/text/decoder.rs index 6a6bc8d0..cc7e201a 100644 --- a/buffa/src/text/decoder.rs +++ b/buffa/src/text/decoder.rs @@ -747,7 +747,7 @@ mod tests { &mut self, tag: crate::encoding::Tag, buf: &mut impl bytes::Buf, - _depth: u32, + _ctx: crate::DecodeContext<'_>, ) -> Result<(), crate::DecodeError> { crate::encoding::skip_field(tag, buf) } @@ -1268,7 +1268,7 @@ mod tests { &mut self, t: crate::encoding::Tag, b: &mut impl bytes::Buf, - _: u32, + _: crate::DecodeContext<'_>, ) -> Result<(), crate::DecodeError> { crate::encoding::skip_field(t, b) } diff --git a/buffa/src/type_registry.rs b/buffa/src/type_registry.rs index 7a4c692f..a634a88e 100644 --- a/buffa/src/type_registry.rs +++ b/buffa/src/type_registry.rs @@ -730,7 +730,7 @@ mod tests { &mut self, tag: crate::encoding::Tag, buf: &mut impl bytes::Buf, - _: u32, + _: crate::DecodeContext<'_>, ) -> Result<(), crate::DecodeError> { if tag.field_number() == 1 && tag.wire_type() == crate::encoding::WireType::Varint { self.n = crate::encoding::decode_varint(buf)? as i32; diff --git a/buffa/src/unknown_fields.rs b/buffa/src/unknown_fields.rs index 4e46a783..8172e9a1 100644 --- a/buffa/src/unknown_fields.rs +++ b/buffa/src/unknown_fields.rs @@ -74,8 +74,11 @@ impl UnknownFields { /// Decode a concatenation of wire-format fields into [`UnknownFields`]. /// /// Reads tag/data pairs until `data` is exhausted. Each field is decoded - /// via [`decode_unknown_field`](crate::encoding::decode_unknown_field) with - /// the full [`RECURSION_LIMIT`](crate::message::RECURSION_LIMIT) budget. + /// via [`decode_unknown_field`](crate::encoding::decode_unknown_field) + /// with the full [`RECURSION_LIMIT`](crate::message::RECURSION_LIMIT) + /// depth budget and a fresh + /// [`DEFAULT_UNKNOWN_FIELD_LIMIT`](crate::DEFAULT_UNKNOWN_FIELD_LIMIT) + /// unknown-field allowance. /// /// Used by [`GroupCodec`](crate::extension::codecs::GroupCodec) to turn a /// message's encoded bytes back into the inner-field representation that @@ -84,14 +87,17 @@ impl UnknownFields { /// # Errors /// /// Returns [`DecodeError`](crate::DecodeError) if `data` contains a - /// malformed tag, truncated field, or exceeds the recursion limit. + /// malformed tag, truncated field, or exceeds the recursion limit or + /// unknown-field limit. pub fn decode_from_slice(mut data: &[u8]) -> Result { use crate::encoding::{decode_unknown_field, Tag}; - use crate::message::RECURSION_LIMIT; + use crate::message::{DecodeContext, DEFAULT_UNKNOWN_FIELD_LIMIT, RECURSION_LIMIT}; + let limit = core::cell::Cell::new(DEFAULT_UNKNOWN_FIELD_LIMIT); + let ctx = DecodeContext::new(RECURSION_LIMIT, &limit); let mut out = Self::new(); while !data.is_empty() { let tag = Tag::decode(&mut data)?; - out.push(decode_unknown_field(tag, &mut data, RECURSION_LIMIT)?); + out.push(decode_unknown_field(tag, &mut data, ctx)?); } Ok(out) } diff --git a/buffa/src/view.rs b/buffa/src/view.rs index e1b14af7..da751d9f 100644 --- a/buffa/src/view.rs +++ b/buffa/src/view.rs @@ -121,13 +121,20 @@ pub trait MessageView<'a>: Sized { /// must ensure the buffer is contiguous (e.g., `&[u8]` or `bytes::Bytes`). fn decode_view(buf: &'a [u8]) -> Result; - /// Decode a view with a custom recursion depth limit. + /// Decode a view under custom decode limits. /// /// Used by [`DecodeOptions::decode_view`](crate::DecodeOptions::decode_view) - /// to pass a non-default recursion budget. The default implementation - /// delegates to [`decode_view`](Self::decode_view) (ignoring the limit); - /// generated code overrides this to call `_decode_depth(buf, depth)`. - fn decode_view_with_limit(buf: &'a [u8], _depth: u32) -> Result { + /// to pass a non-default recursion depth and unknown-field allowance. + /// The default implementation delegates to + /// [`decode_view`](Self::decode_view) and **ignores the context** — + /// a hand-written `MessageView` that recurses or preserves unknown + /// fields must override this method to honor the limits configured on + /// `DecodeOptions`. Generated code always overrides it, calling + /// `_decode_ctx(buf, ctx)`. + fn decode_view_with_ctx( + buf: &'a [u8], + _ctx: crate::DecodeContext<'_>, + ) -> Result { Self::decode_view(buf) } @@ -135,7 +142,15 @@ pub trait MessageView<'a>: Sized { /// /// This allocates and copies all borrowed fields. Equivalent to /// [`to_owned_from_source(None)`](Self::to_owned_from_source). - fn to_owned_message(&self) -> Self::Owned; + /// + /// # Errors + /// + /// Returns an error if re-materializing preserved unknown fields fails — + /// notably [`DecodeError::UnknownFieldLimitExceeded`] when the view + /// holds more unknown fields than the allowance it was decoded under + /// (each owned `UnknownField` counts, unlike the coalesced spans the + /// view itself stores). + fn to_owned_message(&self) -> Result; /// Convert this view to the owned message type, optionally slicing /// `bytes::Bytes`-typed fields from `source` instead of copying. @@ -150,7 +165,11 @@ pub trait MessageView<'a>: Sized { /// Generated view types override this; the default delegates to /// [`to_owned_message`](Self::to_owned_message) so hand-written impls /// need only provide that method. - fn to_owned_from_source(&self, source: Option<&Bytes>) -> Self::Owned { + /// + /// # Errors + /// + /// Same contract as [`to_owned_message`](Self::to_owned_message). + fn to_owned_from_source(&self, source: Option<&Bytes>) -> Result { let _ = source; self.to_owned_message() } @@ -930,11 +949,35 @@ impl<'a, K, V> IntoIterator for MapView<'a, K, V> { /// A borrowed view of unknown fields. /// /// Stores raw byte slices from the input buffer rather than decoded values, -/// enabling zero-copy round-tripping of unknown fields. -#[derive(Clone, Debug, Default)] +/// enabling zero-copy round-tripping of unknown fields. Each stored span +/// holds **one or more consecutive** complete `(tag, value)` records: +/// adjacent unknown fields are coalesced into a single span, so a long run +/// of unknown fields costs one `Vec` slot rather than one per field. +#[derive(Clone, Default)] pub struct UnknownFieldsView<'a> { - /// Raw (tag, value) byte spans from the input buffer. + /// Raw byte spans from the input buffer, each one or more complete + /// `(tag, value)` records. raw_spans: alloc::vec::Vec<&'a [u8]>, + /// The input-buffer tail starting at the first byte of the last span, + /// kept so [`push_record`](Self::push_record) can extend that span over + /// an adjacent record by re-slicing `last_tail` — never by widening the + /// narrowed span reference, which would be provenance-unsound. + last_tail: Option<&'a [u8]>, + /// The unknown-field allowance remaining when this view's first record + /// was pushed — the budget [`to_owned`](Self::to_owned) re-materializes + /// under, so a tight decode-time limit carries through conversion. + to_owned_allowance: Option, +} + +// Manual impl: `last_tail` is an internal coalescing cursor that extends to +// the end of the input buffer — deriving Debug would dump the remaining +// message bytes on every `{:?}` print. +impl core::fmt::Debug for UnknownFieldsView<'_> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.debug_struct("UnknownFieldsView") + .field("raw_spans", &self.raw_spans) + .finish_non_exhaustive() + } } impl<'a> UnknownFieldsView<'a> { @@ -946,6 +989,55 @@ impl<'a> UnknownFieldsView<'a> { #[doc(hidden)] pub fn push_raw(&mut self, span: &'a [u8]) { self.raw_spans.push(span); + // A manually pushed span has no known position in the input buffer, + // so coalescing must not extend it. + self.last_tail = None; + } + + /// Record one unknown wire record of `span_len` bytes starting at the + /// head of `tail`, where `tail` extends from the record's first byte to + /// the end of the input buffer. + /// + /// If the record starts exactly where the previous one ended, the + /// previous span is extended in place (no allocation, no slot consumed); + /// otherwise a new span is pushed and one slot of `ctx`'s unknown-field + /// allowance is consumed. + /// + /// # Errors + /// + /// Returns [`DecodeError::UnknownFieldLimitExceeded`] when a new span is + /// needed but the allowance is exhausted, or + /// [`DecodeError::UnexpectedEof`] if `span_len` exceeds `tail`. + #[doc(hidden)] + pub fn push_record( + &mut self, + tail: &'a [u8], + span_len: usize, + ctx: crate::DecodeContext<'_>, + ) -> Result<(), crate::DecodeError> { + if span_len > tail.len() { + return Err(crate::DecodeError::UnexpectedEof); + } + if self.to_owned_allowance.is_none() { + self.to_owned_allowance = Some(ctx.remaining_unknown_fields()); + } + if let (Some(last), Some(prev_tail)) = (self.raw_spans.last_mut(), self.last_tail) { + let prev_len = last.len(); + // Contiguous if the new record begins exactly one past the end + // of the previous span. Both checks are plain pointer/length + // comparisons; the extension below re-slices `prev_tail`, whose + // provenance covers the combined range. + if prev_tail.len() >= prev_len + span_len + && core::ptr::eq(prev_tail[prev_len..].as_ptr(), tail.as_ptr()) + { + *last = &prev_tail[..prev_len + span_len]; + return Ok(()); + } + } + ctx.register_unknown_field()?; + self.raw_spans.push(&tail[..span_len]); + self.last_tail = Some(tail); + Ok(()) } /// Returns `true` if no unknown fields were recorded. @@ -958,9 +1050,9 @@ impl<'a> UnknownFieldsView<'a> { self.raw_spans.iter().map(|s| s.len()).sum() } - /// Write all unknown-field bytes verbatim. Each span is a complete - /// `(tag, value)` record as it appeared on the wire, so concatenating - /// them produces a valid encoding. + /// Write all unknown-field bytes verbatim. Each span holds one or more + /// complete `(tag, value)` records as they appeared on the wire, so + /// concatenating the spans produces a valid encoding. pub fn write_to(&self, buf: &mut impl BufMut) { for span in &self.raw_spans { buf.put_slice(span); @@ -969,9 +1061,18 @@ impl<'a> UnknownFieldsView<'a> { /// Convert to an owned [`UnknownFields`](crate::UnknownFields) by parsing all stored raw byte spans. /// - /// Each span is a complete (tag + value) record as it appeared on the wire. - /// Parsing uses [`crate::encoding::decode_unknown_field`] with the full - /// recursion limit so deeply nested group fields are handled correctly. + /// Each span holds one or more consecutive (tag + value) records as they + /// appeared on the wire. Parsing uses + /// [`crate::encoding::decode_unknown_field`] with the full recursion + /// limit so deeply nested group fields are handled correctly, and the + /// unknown-field allowance that remained when this view recorded its + /// first unknown field — so a tight decode-time limit carries through + /// conversion. Views built manually (via [`push_raw`](Self::push_raw)) + /// fall back to + /// [`DEFAULT_UNKNOWN_FIELD_LIMIT`](crate::DEFAULT_UNKNOWN_FIELD_LIMIT). + /// A coalesced span re-materializes one owned `UnknownField` per + /// record, so this conversion is where a long run of unknown fields + /// actually allocates — and where the limit is enforced per field. /// /// # Errors /// @@ -980,12 +1081,19 @@ impl<'a> UnknownFieldsView<'a> { pub fn to_owned(&self) -> Result { use crate::encoding::{decode_unknown_field, Tag}; + let limit = core::cell::Cell::new( + self.to_owned_allowance + .unwrap_or(crate::DEFAULT_UNKNOWN_FIELD_LIMIT), + ); + let ctx = crate::DecodeContext::new(crate::RECURSION_LIMIT, &limit); let mut out = crate::UnknownFields::new(); for span in &self.raw_spans { let mut cur: &[u8] = span; - let tag = Tag::decode(&mut cur)?; - let field = decode_unknown_field(tag, &mut cur, crate::RECURSION_LIMIT)?; - out.push(field); + while !cur.is_empty() { + let tag = Tag::decode(&mut cur)?; + let field = decode_unknown_field(tag, &mut cur, ctx)?; + out.push(field); + } } Ok(out) } @@ -1189,7 +1297,12 @@ where /// `bytes::Bytes`-typed fields are produced via [`Bytes::slice_ref`] /// into the retained buffer (zero-copy); other borrowed fields are /// allocated and copied. - pub fn to_owned_message(&self) -> V::Owned { + /// + /// # Errors + /// + /// 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)) } @@ -1542,6 +1655,122 @@ mod tests { assert_eq!(collected, alloc::vec![1, 2]); } + // ── UnknownFieldsView::push_record (coalescing + limit) ──────────── + + /// A test context at full depth with `n` unknown-field slots, leaking + /// the cell so the context can outlive this helper. + fn record_ctx(n: usize) -> crate::DecodeContext<'static> { + let limit = alloc::boxed::Box::leak(alloc::boxed::Box::new(core::cell::Cell::new(n))); + crate::DecodeContext::new(crate::RECURSION_LIMIT, limit) + } + + #[test] + fn push_record_coalesces_adjacent_records() { + // Buffer holds three consecutive 2-byte records. + let buf: &[u8] = &[0x08, 0x00, 0x08, 0x01, 0x08, 0x02]; + let ctx = record_ctx(1); // one slot is enough for a contiguous run + let mut ufv = UnknownFieldsView::new(); + ufv.push_record(&buf[0..], 2, ctx).unwrap(); + ufv.push_record(&buf[2..], 2, ctx).unwrap(); + ufv.push_record(&buf[4..], 2, ctx).unwrap(); + assert_eq!(ufv.encoded_len(), 6); + let mut out = alloc::vec::Vec::new(); + ufv.write_to(&mut out); + assert_eq!(out, buf); + assert_eq!(ctx.remaining_unknown_fields(), 0, "single slot consumed"); + } + + #[test] + fn push_record_non_adjacent_records_use_separate_slots() { + let buf: &[u8] = &[0x08, 0x00, 0xFF, 0x08, 0x01]; + let ctx = record_ctx(2); + let mut ufv = UnknownFieldsView::new(); + ufv.push_record(&buf[0..], 2, ctx).unwrap(); + // Skip buf[2] — the next record is not adjacent to the previous one. + ufv.push_record(&buf[3..], 2, ctx).unwrap(); + assert_eq!(ufv.encoded_len(), 4); + assert_eq!(ctx.remaining_unknown_fields(), 0, "two slots consumed"); + } + + #[test] + fn push_record_enforces_limit_for_new_spans() { + let buf: &[u8] = &[0x08, 0x00, 0xFF, 0x08, 0x01]; + let ctx = record_ctx(1); + let mut ufv = UnknownFieldsView::new(); + ufv.push_record(&buf[0..], 2, ctx).unwrap(); + assert_eq!( + ufv.push_record(&buf[3..], 2, ctx), + Err(crate::DecodeError::UnknownFieldLimitExceeded) + ); + // Extending the existing span never needs a slot — even at zero + // remaining, an adjacent record still coalesces. + ufv.push_record(&buf[2..], 1, ctx) + .expect("adjacent record coalesces without a slot"); + } + + #[test] + fn push_raw_disables_coalescing_for_next_record() { + let buf: &[u8] = &[0x08, 0x00, 0x08, 0x01]; + let ctx = record_ctx(2); + let mut ufv = UnknownFieldsView::new(); + ufv.push_raw(&buf[0..2]); + // Adjacent on the wire, but push_raw cleared the tail, so this must + // open a fresh span (a manual span has no trusted buffer position). + ufv.push_record(&buf[2..], 2, ctx).unwrap(); + assert_eq!(ctx.remaining_unknown_fields(), 1); + assert_eq!(ufv.encoded_len(), 4); + } + + #[test] + fn push_record_rejects_span_past_tail_end() { + let buf: &[u8] = &[0x08, 0x00]; + let ctx = record_ctx(1); + let mut ufv = UnknownFieldsView::new(); + assert_eq!( + ufv.push_record(buf, 3, ctx), + Err(crate::DecodeError::UnexpectedEof) + ); + } + + #[test] + fn coalesced_span_to_owned_parses_every_record() { + let buf: &[u8] = &[0x08, 0x00, 0x08, 0x01, 0x08, 0x02]; + let ctx = record_ctx(3); + let mut ufv = UnknownFieldsView::new(); + for i in 0..3 { + ufv.push_record(&buf[2 * i..], 2, ctx).unwrap(); + } + let owned = ufv.to_owned().unwrap(); + assert_eq!(owned.iter().count(), 3, "all records parsed"); + } + + #[test] + fn to_owned_enforces_decode_time_allowance() { + // Decoded under an allowance of 1: the coalesced span holds three + // records, so materializing them as owned fields must fail — the + // decode-time limit carries through conversion. + let buf: &[u8] = &[0x08, 0x00, 0x08, 0x01, 0x08, 0x02]; + let ctx = record_ctx(1); + let mut ufv = UnknownFieldsView::new(); + for i in 0..3 { + ufv.push_record(&buf[2 * i..], 2, ctx).unwrap(); + } + assert_eq!( + ufv.to_owned(), + Err(crate::DecodeError::UnknownFieldLimitExceeded) + ); + } + + #[test] + fn to_owned_of_manual_view_uses_default_allowance() { + // push_raw leaves no captured allowance; to_owned falls back to the + // default limit. + let mut ufv = UnknownFieldsView::new(); + ufv.push_raw(&[0x08, 0x00]); + let owned = ufv.to_owned().unwrap(); + assert_eq!(owned.iter().count(), 1); + } + #[test] fn repeated_view_reserve_grows_capacity() { let mut rv = RepeatedView::::default(); @@ -1872,7 +2101,7 @@ mod tests { &mut self, tag: crate::encoding::Tag, buf: &mut impl bytes::Buf, - _depth: u32, + _ctx: crate::DecodeContext<'_>, ) -> Result<(), DecodeError> { match tag.field_number() { 1 => self.id = crate::types::decode_int32(buf)?, @@ -1919,11 +2148,11 @@ mod tests { Ok(view) } - fn to_owned_message(&self) -> SimpleMessage { - SimpleMessage { + fn to_owned_message(&self) -> Result { + Ok(SimpleMessage { id: self.id, name: self.name.into(), - } + }) } } @@ -1975,7 +2204,7 @@ 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(); + let owned = view.to_owned_message().unwrap(); assert_eq!(owned.id, 7); assert_eq!(owned.name, "world"); @@ -2041,7 +2270,7 @@ mod tests { assert_eq!(view.reborrow().id, 99); assert_eq!(view.reborrow().name, "roundtrip"); - let back = view.to_owned_message(); + let back = view.to_owned_message().unwrap(); assert_eq!(back, msg); } @@ -2132,7 +2361,7 @@ mod tests { }) } - fn to_owned_message(&self) -> SimpleMessage { + fn to_owned_message(&self) -> Result { self.inner.to_owned_message() } } diff --git a/conformance/Cargo.lock b/conformance/Cargo.lock index 532b08f0..d59a2758 100644 --- a/conformance/Cargo.lock +++ b/conformance/Cargo.lock @@ -32,7 +32,7 @@ dependencies = [ [[package]] name = "buffa" -version = "0.6.0" +version = "0.7.1" dependencies = [ "base64", "bytes", @@ -48,7 +48,7 @@ dependencies = [ [[package]] name = "buffa-build" -version = "0.6.0" +version = "0.7.1" dependencies = [ "buffa", "buffa-codegen", @@ -57,7 +57,7 @@ dependencies = [ [[package]] name = "buffa-codegen" -version = "0.6.0" +version = "0.7.1" dependencies = [ "buffa", "buffa-descriptor", @@ -70,7 +70,7 @@ dependencies = [ [[package]] name = "buffa-descriptor" -version = "0.6.0" +version = "0.7.1" dependencies = [ "buffa", "serde", @@ -79,7 +79,7 @@ dependencies = [ [[package]] name = "buffa-types" -version = "0.6.0" +version = "0.7.1" dependencies = [ "buffa", "buffa-descriptor", diff --git a/conformance/Dockerfile b/conformance/Dockerfile index bac267ff..9097222f 100644 --- a/conformance/Dockerfile +++ b/conformance/Dockerfile @@ -12,7 +12,7 @@ ARG TOOLS_IMAGE=ghcr.io/anthropics/buffa/tools:v33.5 FROM ${TOOLS_IMAGE} AS tools # ── Stage 2: build our conformance binary ───────────────────────────────── -FROM rust:1.85-slim AS rust-builder +FROM rust:1.87-slim AS rust-builder # System deps for linking. RUN apt-get update && apt-get install -y pkg-config \ diff --git a/conformance/src/main.rs b/conformance/src/main.rs index 7c9e1518..cf4a2646 100644 --- a/conformance/src/main.rs +++ b/conformance/src/main.rs @@ -153,7 +153,7 @@ where V: buffa::MessageView<'a>, { let view = V::decode_view(bytes).map_err(|e| format!("{e}"))?; - Ok(view.to_owned_message()) + view.to_owned_message().map_err(|e| format!("{e}")) } // ── View-JSON mode ─────────────────────────────────────────────────────── diff --git a/docs/guide.md b/docs/guide.md index 87e909c8..ec27cacc 100644 --- a/docs/guide.md +++ b/docs/guide.md @@ -904,6 +904,9 @@ for the full list of variants (the enum is `#[non_exhaustive]`). Common cases: - `WireTypeMismatch` — field on wire has a different type than schema expects - `RecursionLimitExceeded` — too-deeply-nested message (attack or bug) - `MessageTooLarge` — exceeds configured size limit +- `UnknownFieldLimitExceeded` — the message contains more unknown fields + than the configured limit (default 1,000,000); raise with + `.with_unknown_field_limit(n)` if your messages legitimately carry more ### Decode options @@ -932,8 +935,23 @@ let view = DecodeOptions::new() |--------|---------|-------------| | `.with_recursion_limit(n)` | 100 | Max nesting depth for sub-messages | | `.with_max_message_size(n)` | 2 GiB - 1 | Max total input size in bytes | +| `.with_unknown_field_limit(n)` | 1,000,000 | Max unknown fields materialized per decode | -The default `Message::decode` / `decode_from_slice` methods use the defaults (100 depth, 2 GiB max). `DecodeOptions` is only needed when you want tighter limits. +The unknown-field limit exists because unknown fields can occupy far more +memory decoded than encoded — each one costs a ~40-byte in-memory slot, so a +run of minimal 2-byte varint fields amplifies ~20× and an input-size cap +alone does not bound decoder memory. The limit caps that overhead at roughly +`n × 40` bytes per decode call and is enforced by default — a flood of +unknown fields fails with `UnknownFieldLimitExceeded` instead of exhausting +the heap. (Unknown length-delimited *payload* bytes are not counted: they +are bounded by the input size, which `.with_max_message_size(n)` governs.) +Raise the limit if you decode trusted messages that legitimately carry more +unknown fields (e.g. a proxy forwarding messages with a huge unpacked +repeated field from a much newer schema). + +Zero-copy view decoding (`decode_view`) honors the same limit, but counts **coalesced spans** — one per contiguous run of unknown fields (~16 bytes each) — rather than individual fields, since views store unknown fields as borrowed byte ranges instead of materializing them. The same numeric limit is therefore more permissive for views; the per-field cost is only paid (under the default limit) when converting a view to an owned message. + +The default `Message::decode` / `decode_from_slice` methods use the defaults (100 depth, 2 GiB max input, 1M unknown fields). `DecodeOptions` is only needed when you want different limits. ## Zero-copy views @@ -1927,7 +1945,7 @@ impl Message for Int64Range { &mut self, tag: buffa::encoding::Tag, buf: &mut impl bytes::Buf, - _depth: u32, + _ctx: buffa::DecodeContext<'_>, ) -> Result<(), DecodeError> { match tag.field_number() { 1 => self.inner.start = buffa::types::decode_int64(buf)?, diff --git a/examples/addressbook/Cargo.lock b/examples/addressbook/Cargo.lock index 5086f235..e03648ff 100644 --- a/examples/addressbook/Cargo.lock +++ b/examples/addressbook/Cargo.lock @@ -14,21 +14,34 @@ version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" +[[package]] +name = "borsh" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfd1e3f8955a5d7de9fab72fc8373fade9fb8a703968cb200ae3dc6cf08e185a" +dependencies = [ + "bytes", + "cfg_aliases", +] + [[package]] name = "buffa" -version = "0.5.0" +version = "0.7.1" dependencies = [ "bytes", + "compact_str", + "ecow", "hashbrown 0.15.5", "once_cell", "serde", "serde_json", + "smol_str", "thiserror", ] [[package]] name = "buffa-build" -version = "0.5.0" +version = "0.7.1" dependencies = [ "buffa", "buffa-codegen", @@ -37,7 +50,7 @@ dependencies = [ [[package]] name = "buffa-codegen" -version = "0.5.0" +version = "0.7.1" dependencies = [ "buffa", "buffa-descriptor", @@ -50,14 +63,16 @@ dependencies = [ [[package]] name = "buffa-descriptor" -version = "0.5.0" +version = "0.7.1" dependencies = [ "buffa", + "serde", + "serde_json", ] [[package]] name = "buffa-types" -version = "0.5.0" +version = "0.7.1" dependencies = [ "buffa", "bytes", @@ -72,12 +87,47 @@ version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" +[[package]] +name = "castaway" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dec551ab6e7578819132c713a93c022a05d60159dc86e7a7050223577484c55a" +dependencies = [ + "rustversion", +] + [[package]] name = "cfg-if" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + +[[package]] +name = "compact_str" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dfdd1c2274d9aa354115b09dc9a901d6c5576818cdf70d14cae2bdb47df00ab" +dependencies = [ + "castaway", + "cfg-if", + "itoa", + "rustversion", + "ryu", + "static_assertions", +] + +[[package]] +name = "ecow" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78e4f79b296fbaab6ce2e22d52cb4c7f010fe0ebe7a32e34fa25885fd797bd02" + [[package]] name = "equivalent" version = "1.0.2" @@ -256,6 +306,18 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + +[[package]] +name = "ryu" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" + [[package]] name = "semver" version = "1.0.27" @@ -269,6 +331,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" dependencies = [ "serde_core", + "serde_derive", ] [[package]] @@ -304,6 +367,22 @@ dependencies = [ "zmij", ] +[[package]] +name = "smol_str" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9676b89cd56310a87b93dec47b11af744f34d5fc9f367b829474eec0a891350d" +dependencies = [ + "borsh", + "serde", +] + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + [[package]] name = "syn" version = "2.0.117" diff --git a/examples/bsr-quickstart/Cargo.lock b/examples/bsr-quickstart/Cargo.lock index abfd714f..9e688c8f 100644 --- a/examples/bsr-quickstart/Cargo.lock +++ b/examples/bsr-quickstart/Cargo.lock @@ -8,22 +8,35 @@ version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" +[[package]] +name = "borsh" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfd1e3f8955a5d7de9fab72fc8373fade9fb8a703968cb200ae3dc6cf08e185a" +dependencies = [ + "bytes", + "cfg_aliases", +] + [[package]] name = "buffa" -version = "0.5.2" +version = "0.7.1" dependencies = [ "base64", "bytes", + "compact_str", + "ecow", "hashbrown", "once_cell", "serde", "serde_json", + "smol_str", "thiserror", ] [[package]] name = "buffa-types" -version = "0.5.2" +version = "0.7.1" dependencies = [ "buffa", "bytes", @@ -38,6 +51,51 @@ version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" +[[package]] +name = "castaway" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dec551ab6e7578819132c713a93c022a05d60159dc86e7a7050223577484c55a" +dependencies = [ + "rustversion", +] + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + +[[package]] +name = "compact_str" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dfdd1c2274d9aa354115b09dc9a901d6c5576818cdf70d14cae2bdb47df00ab" +dependencies = [ + "castaway", + "cfg-if", + "itoa", + "rustversion", + "ryu", + "serde", + "static_assertions", +] + +[[package]] +name = "ecow" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78e4f79b296fbaab6ce2e22d52cb4c7f010fe0ebe7a32e34fa25885fd797bd02" +dependencies = [ + "serde", +] + [[package]] name = "example-bsr-quickstart" version = "0.1.0" @@ -100,6 +158,18 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + +[[package]] +name = "ryu" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" + [[package]] name = "serde" version = "1.0.228" @@ -143,6 +213,22 @@ dependencies = [ "zmij", ] +[[package]] +name = "smol_str" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9676b89cd56310a87b93dec47b11af744f34d5fc9f367b829474eec0a891350d" +dependencies = [ + "borsh", + "serde", +] + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + [[package]] name = "syn" version = "2.0.117" diff --git a/examples/bsr-quickstart/src/gen/example.v1.rs b/examples/bsr-quickstart/src/gen/example.v1.rs index 8e0033d5..76b78235 100644 --- a/examples/bsr-quickstart/src/gen/example.v1.rs +++ b/examples/bsr-quickstart/src/gen/example.v1.rs @@ -8,6 +8,17 @@ pub enum Mood { MOOD_FRIENDLY = 1i32, MOOD_FORMAL = 2i32, } +impl Mood { + ///Idiomatic alias for [`Self::MOOD_UNSPECIFIED`]; `Debug` prints the variant name. + #[allow(non_upper_case_globals)] + pub const Unspecified: Self = Self::MOOD_UNSPECIFIED; + ///Idiomatic alias for [`Self::MOOD_FRIENDLY`]; `Debug` prints the variant name. + #[allow(non_upper_case_globals)] + pub const Friendly: Self = Self::MOOD_FRIENDLY; + ///Idiomatic alias for [`Self::MOOD_FORMAL`]; `Debug` prints the variant name. + #[allow(non_upper_case_globals)] + pub const Formal: Self = Self::MOOD_FORMAL; +} impl ::core::default::Default for Mood { fn default() -> Self { Self::MOOD_UNSPECIFIED @@ -198,6 +209,12 @@ impl ::buffa::DefaultInstance for Greeting { VALUE.get_or_init(|| ::buffa::alloc::boxed::Box::new(Self::default())) } } +impl ::buffa::MessageName for Greeting { + const PACKAGE: &'static str = "example.v1"; + const NAME: &'static str = "Greeting"; + const FULL_NAME: &'static str = "example.v1.Greeting"; + const TYPE_URL: &'static str = "type.googleapis.com/example.v1.Greeting"; +} impl ::buffa::Message for Greeting { /// Returns the total encoded size in bytes. /// @@ -308,7 +325,7 @@ impl ::buffa::Message for Greeting { &mut self, tag: ::buffa::encoding::Tag, buf: &mut impl ::buffa::bytes::Buf, - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result<(), ::buffa::DecodeError> { #[allow(unused_imports)] use ::buffa::bytes::Buf as _; @@ -336,7 +353,7 @@ impl ::buffa::Message for Greeting { ::buffa::Message::merge_length_delimited( self.at.get_or_insert_default(), buf, - depth, + ctx, )?; } 3u32 => { @@ -389,7 +406,7 @@ impl ::buffa::Message for Greeting { } _ => { self.__buffa_unknown_fields - .push(::buffa::encoding::decode_unknown_field(tag, buf, depth)?); + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); } } ::core::result::Result::Ok(()) @@ -649,20 +666,22 @@ pub mod __buffa { pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, } impl<'a> GreetingView<'a> { - /// Decode from `buf`, enforcing a recursion depth limit for nested messages. + /// Decode from `buf` under the limits carried by `ctx` (recursion + /// depth and the shared unknown-field allowance). /// - /// Called by [`::buffa::MessageView::decode_view`] with [`::buffa::RECURSION_LIMIT`] - /// and by generated sub-message decode arms with `depth - 1`. + /// Called by [`::buffa::MessageView::decode_view`] with a fresh + /// default context and by generated sub-message decode arms with + /// `ctx.descend()?`. /// /// **Not part of the public API.** Named with a leading underscore to /// signal that it is for generated-code use only. #[doc(hidden)] - pub fn _decode_depth( + pub fn _decode_ctx( buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result { let mut view = Self::default(); - view._merge_into_view(buf, depth)?; + view._merge_into_view(buf, ctx)?; ::core::result::Result::Ok(view) } /// Merge fields from `buf` into this view (proto merge semantics). @@ -676,9 +695,9 @@ pub mod __buffa { pub fn _merge_into_view( &mut self, buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result<(), ::buffa::DecodeError> { - let _ = depth; + let _ = ctx; #[allow(unused_variables)] let view = self; let mut cur: &'a [u8] = buf; @@ -708,17 +727,15 @@ pub mod __buffa { actual: tag.wire_type() as u8, }); } - if depth == 0 { - return Err(::buffa::DecodeError::RecursionLimitExceeded); - } + let __sub_ctx = ctx.descend()?; let sub = ::buffa::types::borrow_bytes(&mut cur)?; match view.at.as_mut() { - Some(existing) => existing._merge_into_view(sub, depth - 1)?, + Some(existing) => existing._merge_into_view(sub, __sub_ctx)?, None => { view.at = ::buffa::MessageFieldView::set( - ::buffa_types::google::protobuf::__buffa::view::TimestampView::_decode_depth( + ::buffa_types::google::protobuf::__buffa::view::TimestampView::_decode_ctx( sub, - depth - 1, + __sub_ctx, )?, ); } @@ -779,10 +796,14 @@ pub mod __buffa { ); } _ => { - ::buffa::encoding::skip_field_depth(tag, &mut cur, depth)?; + ::buffa::encoding::skip_field_depth( + tag, + &mut cur, + ctx.depth(), + )?; let span_len = before_tag.len() - cur.len(); view.__buffa_unknown_fields - .push_raw(&before_tag[..span_len]); + .push_record(before_tag, span_len, ctx)?; } } } @@ -794,32 +815,40 @@ pub mod __buffa { fn decode_view( buf: &'a [u8], ) -> ::core::result::Result { - Self::_decode_depth(buf, ::buffa::RECURSION_LIMIT) + let __limit = ::core::cell::Cell::new( + ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, + ); + Self::_decode_ctx( + buf, + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit), + ) } - fn decode_view_with_limit( + fn decode_view_with_ctx( buf: &'a [u8], - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result { - Self::_decode_depth(buf, depth) + Self::_decode_ctx(buf, ctx) } - fn to_owned_message(&self) -> super::super::Greeting { + fn to_owned_message( + &self, + ) -> ::core::result::Result { self.to_owned_from_source(None) } #[allow(clippy::useless_conversion, clippy::needless_update)] fn to_owned_from_source( &self, __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, - ) -> super::super::Greeting { + ) -> ::core::result::Result { #[allow(unused_imports)] use ::buffa::alloc::string::ToString as _; let _ = __buffa_src; - super::super::Greeting { + ::core::result::Result::Ok(super::super::Greeting { text: self.text.to_string(), at: match self.at.as_option() { Some(v) => { ::buffa::MessageField::< ::buffa_types::google::protobuf::Timestamp, - >::some(v.to_owned_from_source(__buffa_src)) + >::some(v.to_owned_from_source(__buffa_src)?) } None => ::buffa::MessageField::none(), }, @@ -846,11 +875,10 @@ pub mod __buffa { }), __buffa_unknown_fields: self .__buffa_unknown_fields - .to_owned() - .unwrap_or_default() + .to_owned()? .into(), ..::core::default::Default::default() - } + }) } } impl<'a> ::buffa::ViewEncode<'a> for GreetingView<'a> { @@ -967,6 +995,61 @@ pub mod __buffa { self.__buffa_unknown_fields.write_to(buf); } } + /// Serializes this view as protobuf JSON. + /// + /// Implicit-presence fields with default values are omitted, `required` + /// fields are always emitted, explicit-presence (`optional`) fields are + /// emitted only when set, bytes fields are base64-encoded, and enum + /// values are their proto name strings. + /// + /// This impl uses `serialize_map(None)` because the number of emitted + /// fields depends on default-omission rules; serializers that require + /// known map lengths (e.g. `bincode`) will return a runtime error. + /// Use the owned message type for those formats. + impl<'__a> ::serde::Serialize for GreetingView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + if !::buffa::json_helpers::skip_if::is_empty_str(self.text) { + __map.serialize_entry("text", self.text)?; + } + { + if let ::core::option::Option::Some(__v) = self.at.as_option() { + __map.serialize_entry("at", __v)?; + } + } + if !::buffa::json_helpers::skip_if::is_default_enum_value(&self.mood) { + __map.serialize_entry("mood", &self.mood)?; + } + if !self.tags.is_empty() { + __map.serialize_entry("tags", &*self.tags)?; + } + if let ::core::option::Option::Some(ref __ov) = self.recipient { + match __ov { + super::super::__buffa::view::oneof::greeting::Recipient::Name( + v, + ) => { + __map.serialize_entry("name", v)?; + } + super::super::__buffa::view::oneof::greeting::Recipient::Everyone( + v, + ) => { + __map.serialize_entry("everyone", v)?; + } + } + } + __map.end() + } + } + impl<'a> ::buffa::MessageName for GreetingView<'a> { + const PACKAGE: &'static str = "example.v1"; + const NAME: &'static str = "Greeting"; + const FULL_NAME: &'static str = "example.v1.Greeting"; + const TYPE_URL: &'static str = "type.googleapis.com/example.v1.Greeting"; + } impl<'v> ::buffa::DefaultViewInstance for GreetingView<'v> { fn default_view_instance<'a>() -> &'a Self where @@ -985,6 +1068,158 @@ pub mod __buffa { this } } + /** Self-contained, `'static` owned view of a `Greeting` message. + + Wraps [`::buffa::OwnedView`]`<`[`GreetingView`]`<'static>>`: the decoded view and the [`::buffa::bytes::Bytes`] buffer it borrows from travel together, so the handle is `'static` and `Send + Sync` — suitable for async handlers, spawned tasks, and anywhere a `'static` bound is required. + + Field accessors return borrows tied to `&self`. Use [`Self::view`] to get the full [`GreetingView`] when you need struct patterns, iteration helpers, or to pass the view to lifetime-parameterised code.*/ + #[derive(Clone, Debug)] + pub struct GreetingOwnedView(::buffa::OwnedView>); + impl GreetingOwnedView { + /// Decode an owned view from a [`::buffa::bytes::Bytes`] buffer. + /// + /// The view borrows directly from the buffer's data; the buffer is + /// retained inside the returned handle. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer contains invalid + /// protobuf data. + pub fn decode( + bytes: ::buffa::bytes::Bytes, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + GreetingOwnedView(::buffa::OwnedView::decode(bytes)?), + ) + } + /// Decode with custom [`::buffa::DecodeOptions`] (recursion limit, + /// max message size). + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the buffer is invalid or + /// exceeds the configured limits. + pub fn decode_with_options( + bytes: ::buffa::bytes::Bytes, + opts: &::buffa::DecodeOptions, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + GreetingOwnedView( + ::buffa::OwnedView::decode_with_options(bytes, opts)?, + ), + ) + } + /// Build from an owned message via an encode → decode round-trip. + /// + /// # Errors + /// + /// Returns [`::buffa::DecodeError`] if the re-encoded bytes are + /// somehow invalid (should not happen for well-formed messages). + pub fn from_owned( + msg: &super::super::Greeting, + ) -> ::core::result::Result { + ::core::result::Result::Ok( + GreetingOwnedView(::buffa::OwnedView::from_owned(msg)?), + ) + } + /// Borrow the full [`GreetingView`] with its lifetime tied to `&self`. + #[must_use] + pub fn view(&self) -> &GreetingView<'_> { + self.0.reborrow() + } + /// 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 { + self.0.to_owned_message() + } + /// The underlying bytes buffer. + #[must_use] + pub fn bytes(&self) -> &::buffa::bytes::Bytes { + self.0.bytes() + } + /// Consume the handle, returning the underlying bytes buffer. + #[must_use] + pub fn into_bytes(self) -> ::buffa::bytes::Bytes { + self.0.into_bytes() + } + /// The greeting text. + /// + /// Field 1: `text` + #[must_use] + pub fn text(&self) -> &'_ str { + self.0.reborrow().text + } + /// When the greeting was created. + /// + /// Field 2: `at` + #[must_use] + pub fn at( + &self, + ) -> &::buffa::MessageFieldView< + ::buffa_types::google::protobuf::__buffa::view::TimestampView<'_>, + > { + &self.0.reborrow().at + } + /// The mood of the greeting. + /// + /// Field 3: `mood` + #[must_use] + pub fn mood(&self) -> ::buffa::EnumValue { + self.0.reborrow().mood + } + /// Tags applied to the greeting. + /// + /// Field 20: `tags` + #[must_use] + pub fn tags(&self) -> &::buffa::RepeatedView<'_, &'_ str> { + &self.0.reborrow().tags + } + /// Oneof `recipient`. + #[must_use] + pub fn recipient( + &self, + ) -> ::core::option::Option< + &super::super::__buffa::view::oneof::greeting::Recipient<'_>, + > { + self.0.reborrow().recipient.as_ref() + } + } + impl ::core::convert::From<::buffa::OwnedView>> + for GreetingOwnedView { + fn from(inner: ::buffa::OwnedView>) -> Self { + GreetingOwnedView(inner) + } + } + impl ::core::convert::From + for ::buffa::OwnedView> { + fn from(wrapper: GreetingOwnedView) -> Self { + wrapper.0 + } + } + impl ::core::convert::AsRef<::buffa::OwnedView>> + for GreetingOwnedView { + fn as_ref(&self) -> &::buffa::OwnedView> { + &self.0 + } + } + impl ::buffa::HasMessageView for super::super::Greeting { + type View<'a> = GreetingView<'a>; + type ViewHandle = GreetingOwnedView; + } + impl ::serde::Serialize for GreetingOwnedView { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + ::serde::Serialize::serialize(&self.0, __s) + } + } pub mod oneof { #[allow(unused_imports)] use super::*; @@ -1032,10 +1267,6 @@ pub mod __buffa { } } } - pub mod ext { - #[allow(unused_imports)] - use super::*; - } /// Register this package's `Any` type entries and extension entries. pub fn register_types(reg: &mut ::buffa::type_registry::TypeRegistry) { reg.register_json_any(super::__GREETING_JSON_ANY); @@ -1044,4 +1275,6 @@ pub mod __buffa { #[doc(inline)] pub use self::__buffa::view::GreetingView; #[doc(inline)] +pub use self::__buffa::view::GreetingOwnedView; +#[doc(inline)] pub use self::__buffa::register_types; diff --git a/examples/conflicts/Cargo.lock b/examples/conflicts/Cargo.lock index 34ba50ae..dacfe2f5 100644 --- a/examples/conflicts/Cargo.lock +++ b/examples/conflicts/Cargo.lock @@ -14,21 +14,34 @@ version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3" +[[package]] +name = "borsh" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfd1e3f8955a5d7de9fab72fc8373fade9fb8a703968cb200ae3dc6cf08e185a" +dependencies = [ + "bytes", + "cfg_aliases", +] + [[package]] name = "buffa" -version = "0.5.0" +version = "0.7.1" dependencies = [ "bytes", + "compact_str", + "ecow", "hashbrown 0.15.5", "once_cell", "serde", "serde_json", + "smol_str", "thiserror", ] [[package]] name = "buffa-build" -version = "0.5.0" +version = "0.7.1" dependencies = [ "buffa", "buffa-codegen", @@ -37,7 +50,7 @@ dependencies = [ [[package]] name = "buffa-codegen" -version = "0.5.0" +version = "0.7.1" dependencies = [ "buffa", "buffa-descriptor", @@ -50,9 +63,11 @@ dependencies = [ [[package]] name = "buffa-descriptor" -version = "0.5.0" +version = "0.7.1" dependencies = [ "buffa", + "serde", + "serde_json", ] [[package]] @@ -61,12 +76,47 @@ version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" +[[package]] +name = "castaway" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dec551ab6e7578819132c713a93c022a05d60159dc86e7a7050223577484c55a" +dependencies = [ + "rustversion", +] + [[package]] name = "cfg-if" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + +[[package]] +name = "compact_str" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dfdd1c2274d9aa354115b09dc9a901d6c5576818cdf70d14cae2bdb47df00ab" +dependencies = [ + "castaway", + "cfg-if", + "itoa", + "rustversion", + "ryu", + "static_assertions", +] + +[[package]] +name = "ecow" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78e4f79b296fbaab6ce2e22d52cb4c7f010fe0ebe7a32e34fa25885fd797bd02" + [[package]] name = "equivalent" version = "1.0.2" @@ -244,6 +294,18 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + +[[package]] +name = "ryu" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" + [[package]] name = "semver" version = "1.0.28" @@ -257,6 +319,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" dependencies = [ "serde_core", + "serde_derive", ] [[package]] @@ -292,6 +355,22 @@ dependencies = [ "zmij", ] +[[package]] +name = "smol_str" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9676b89cd56310a87b93dec47b11af744f34d5fc9f367b829474eec0a891350d" +dependencies = [ + "borsh", + "serde", +] + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + [[package]] name = "syn" version = "2.0.117" diff --git a/examples/envelope/Cargo.lock b/examples/envelope/Cargo.lock index 432d8412..c170b1a3 100644 --- a/examples/envelope/Cargo.lock +++ b/examples/envelope/Cargo.lock @@ -20,22 +20,35 @@ version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" +[[package]] +name = "borsh" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfd1e3f8955a5d7de9fab72fc8373fade9fb8a703968cb200ae3dc6cf08e185a" +dependencies = [ + "bytes", + "cfg_aliases", +] + [[package]] name = "buffa" -version = "0.5.0" +version = "0.7.1" dependencies = [ "base64", "bytes", + "compact_str", + "ecow", "hashbrown 0.15.5", "once_cell", "serde", "serde_json", + "smol_str", "thiserror", ] [[package]] name = "buffa-build" -version = "0.5.0" +version = "0.7.1" dependencies = [ "buffa", "buffa-codegen", @@ -44,7 +57,7 @@ dependencies = [ [[package]] name = "buffa-codegen" -version = "0.5.0" +version = "0.7.1" dependencies = [ "buffa", "buffa-descriptor", @@ -57,9 +70,11 @@ dependencies = [ [[package]] name = "buffa-descriptor" -version = "0.5.0" +version = "0.7.1" dependencies = [ "buffa", + "serde", + "serde_json", ] [[package]] @@ -68,12 +83,51 @@ version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" +[[package]] +name = "castaway" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dec551ab6e7578819132c713a93c022a05d60159dc86e7a7050223577484c55a" +dependencies = [ + "rustversion", +] + [[package]] name = "cfg-if" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + +[[package]] +name = "compact_str" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dfdd1c2274d9aa354115b09dc9a901d6c5576818cdf70d14cae2bdb47df00ab" +dependencies = [ + "castaway", + "cfg-if", + "itoa", + "rustversion", + "ryu", + "serde", + "static_assertions", +] + +[[package]] +name = "ecow" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78e4f79b296fbaab6ce2e22d52cb4c7f010fe0ebe7a32e34fa25885fd797bd02" +dependencies = [ + "serde", +] + [[package]] name = "equivalent" version = "1.0.2" @@ -254,6 +308,18 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + +[[package]] +name = "ryu" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" + [[package]] name = "semver" version = "1.0.27" @@ -303,6 +369,22 @@ dependencies = [ "zmij", ] +[[package]] +name = "smol_str" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9676b89cd56310a87b93dec47b11af744f34d5fc9f367b829474eec0a891350d" +dependencies = [ + "borsh", + "serde", +] + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + [[package]] name = "syn" version = "2.0.117" diff --git a/examples/logging/Cargo.lock b/examples/logging/Cargo.lock index 066a87f3..1a8ed140 100644 --- a/examples/logging/Cargo.lock +++ b/examples/logging/Cargo.lock @@ -2,21 +2,34 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "borsh" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfd1e3f8955a5d7de9fab72fc8373fade9fb8a703968cb200ae3dc6cf08e185a" +dependencies = [ + "bytes", + "cfg_aliases", +] + [[package]] name = "buffa" -version = "0.5.2" +version = "0.7.1" dependencies = [ "bytes", + "compact_str", + "ecow", "hashbrown", "once_cell", "serde", "serde_json", + "smol_str", "thiserror", ] [[package]] name = "buffa-types" -version = "0.5.2" +version = "0.7.1" dependencies = [ "buffa", "bytes", @@ -31,6 +44,47 @@ version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" +[[package]] +name = "castaway" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dec551ab6e7578819132c713a93c022a05d60159dc86e7a7050223577484c55a" +dependencies = [ + "rustversion", +] + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + +[[package]] +name = "compact_str" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dfdd1c2274d9aa354115b09dc9a901d6c5576818cdf70d14cae2bdb47df00ab" +dependencies = [ + "castaway", + "cfg-if", + "itoa", + "rustversion", + "ryu", + "static_assertions", +] + +[[package]] +name = "ecow" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78e4f79b296fbaab6ce2e22d52cb4c7f010fe0ebe7a32e34fa25885fd797bd02" + [[package]] name = "example-logging" version = "0.1.0" @@ -90,6 +144,18 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + +[[package]] +name = "ryu" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" + [[package]] name = "serde" version = "1.0.228" @@ -132,6 +198,22 @@ dependencies = [ "zmij", ] +[[package]] +name = "smol_str" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9676b89cd56310a87b93dec47b11af744f34d5fc9f367b829474eec0a891350d" +dependencies = [ + "borsh", + "serde", +] + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + [[package]] name = "syn" version = "2.0.117" diff --git a/examples/logging/src/gen/context.v1.context.rs b/examples/logging/src/gen/context.v1.context.rs index 5d3b33f0..cb3a3a8b 100644 --- a/examples/logging/src/gen/context.v1.context.rs +++ b/examples/logging/src/gen/context.v1.context.rs @@ -161,7 +161,7 @@ impl ::buffa::Message for RequestContext { &mut self, tag: ::buffa::encoding::Tag, buf: &mut impl ::buffa::bytes::Buf, - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result<(), ::buffa::DecodeError> { #[allow(unused_imports)] use ::buffa::bytes::Buf as _; @@ -255,7 +255,11 @@ impl ::buffa::Message for RequestContext { val = ::buffa::types::decode_string(buf)?; } _ => { - ::buffa::encoding::skip_field_depth(entry_tag, buf, depth)?; + ::buffa::encoding::skip_field_depth( + entry_tag, + buf, + ctx.depth(), + )?; } } } @@ -273,7 +277,7 @@ impl ::buffa::Message for RequestContext { } _ => { self.__buffa_unknown_fields - .push(::buffa::encoding::decode_unknown_field(tag, buf, depth)?); + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); } } ::core::result::Result::Ok(()) diff --git a/examples/logging/src/gen/log.v1.log.rs b/examples/logging/src/gen/log.v1.log.rs index 0521f2d8..32dea651 100644 --- a/examples/logging/src/gen/log.v1.log.rs +++ b/examples/logging/src/gen/log.v1.log.rs @@ -277,7 +277,7 @@ impl ::buffa::Message for LogEntry { &mut self, tag: ::buffa::encoding::Tag, buf: &mut impl ::buffa::bytes::Buf, - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result<(), ::buffa::DecodeError> { #[allow(unused_imports)] use ::buffa::bytes::Buf as _; @@ -295,7 +295,7 @@ impl ::buffa::Message for LogEntry { ::buffa::Message::merge_length_delimited( self.timestamp.get_or_insert_default(), buf, - depth, + ctx, )?; } 2u32 => { @@ -341,7 +341,7 @@ impl ::buffa::Message for LogEntry { ::buffa::Message::merge_length_delimited( self.context.get_or_insert_default(), buf, - depth, + ctx, )?; } 6u32 => { @@ -391,7 +391,11 @@ impl ::buffa::Message for LogEntry { val = ::buffa::types::decode_string(buf)?; } _ => { - ::buffa::encoding::skip_field_depth(entry_tag, buf, depth)?; + ::buffa::encoding::skip_field_depth( + entry_tag, + buf, + ctx.depth(), + )?; } } } @@ -409,7 +413,7 @@ impl ::buffa::Message for LogEntry { } _ => { self.__buffa_unknown_fields - .push(::buffa::encoding::decode_unknown_field(tag, buf, depth)?); + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); } } ::core::result::Result::Ok(()) @@ -509,7 +513,7 @@ impl ::buffa::Message for LogBatch { &mut self, tag: ::buffa::encoding::Tag, buf: &mut impl ::buffa::bytes::Buf, - depth: u32, + ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result<(), ::buffa::DecodeError> { #[allow(unused_imports)] use ::buffa::bytes::Buf as _; @@ -525,12 +529,12 @@ impl ::buffa::Message for LogBatch { }); } let mut elem = ::core::default::Default::default(); - ::buffa::Message::merge_length_delimited(&mut elem, buf, depth)?; + ::buffa::Message::merge_length_delimited(&mut elem, buf, ctx)?; self.entries.push(elem); } _ => { self.__buffa_unknown_fields - .push(::buffa::encoding::decode_unknown_field(tag, buf, depth)?); + .push(::buffa::encoding::decode_unknown_field(tag, buf, ctx)?); } } ::core::result::Result::Ok(())