diff --git a/.changes/unreleased/fixed-20260909-125500.yaml b/.changes/unreleased/fixed-20260909-125500.yaml new file mode 100644 index 00000000..8c32b920 --- /dev/null +++ b/.changes/unreleased/fixed-20260909-125500.yaml @@ -0,0 +1,4 @@ +kind: Fixed +body: |- + **`examples/bsr-quickstart` builds again** (#427). Its checked-in generated code had been hand-patched since it was generated from the v0.5.2 plugin, so it matched neither that plugin nor the current runtime. It is now regenerated from the `buf.build/anthropics/buffa:v0.9.2` plugin and depends on `buffa` / `buffa-types` 0.9.2 from crates.io, and CI builds it. +time: 2026-09-09T12:55:00.000000000-07:00 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a6021872..1e0648eb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -93,6 +93,15 @@ jobs: - name: Shared descriptor pool compile run: cargo test -p buffa-codegen --test shared_pool_compile -- --ignored + # `examples/bsr-quickstart` is outside the workspace, and its `src/gen/` + # is checked-in output from the published BSR plugin, not in-tree + # codegen. Its runtime deps are pinned to the plugin's release (see its + # `Cargo.toml`), so this fails if the pins diverge or `src/gen/` is + # hand-edited. `--locked` keeps new upstream releases of its transitive + # deps from changing the result. (#427) + - name: Check bsr-quickstart example + run: cargo check --locked --manifest-path examples/bsr-quickstart/Cargo.toml + # ── Markdown lint ──────────────────────────────────────────────────────── # Same pinned markdownlint-cli version as `task lint-md`. Node is # preinstalled on ubuntu-latest so no setup-node step is needed. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ffec0459..612856be 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -134,6 +134,8 @@ Three sets of generated code are checked into the repo and **must be regenerated 3. **Logging example** (`examples/logging/src/gen/`): Regenerate with `task gen-logging-example` (requires `buf` on PATH). +The `bsr-quickstart` example's `examples/bsr-quickstart/src/gen/` is the exception: it holds output from the *published* BSR plugin, so codegen changes do not regenerate it. Once the `buf.build/anthropics/buffa` plugin for a new release is published, bump the plugin pin in its `buf.gen.yaml` and the `buffa` / `buffa-types` versions in its `Cargo.toml` together, then run `task gen-bsr-quickstart-example`. + CI (`check-generated-code` job) will fail if checked-in generated code is stale. ## Cross-Target Checks diff --git a/Taskfile.yml b/Taskfile.yml index 5d7901cb..2cc81f63 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -667,17 +667,19 @@ tasks: consumer-facing remote-plugin workflow, so it deliberately uses the published plugin rather than the in-tree `protoc-gen-buffa`. The plugin version is pinned in `buf.gen.yaml` for reproducible - output — bump the pin and re-run this task when a new BSR plugin - release ships, not after every codegen change. `src/gen/mod.rs` is - hand-written and not touched by buf. + output, and the example's `Cargo.toml` pins `buffa` / `buffa-types` + to the same release. When a new BSR plugin release ships, bump all + three together and re-run this task — not after every codegen + change. `src/gen/mod.rs` is hand-written and not touched by buf. dir: examples/bsr-quickstart cmds: - rm -f src/gen/example.v1.rs - buf generate # The examples are independent cargo projects (own Cargo.toml, own target/), - # not workspace members — they declare path deps on the workspace crates to - # mirror a downstream consumer's setup. + # not workspace members. Most declare path deps on the workspace crates to + # mirror a downstream consumer's setup; bsr-quickstart instead depends on the + # crates.io release matching its BSR plugin pin. build-examples: desc: Build all example binaries. diff --git a/examples/bsr-quickstart/Cargo.lock b/examples/bsr-quickstart/Cargo.lock index 9e688c8f..8fcd8367 100644 --- a/examples/bsr-quickstart/Cargo.lock +++ b/examples/bsr-quickstart/Cargo.lock @@ -9,37 +9,38 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] -name = "borsh" -version = "1.6.1" +name = "bitflags" +version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfd1e3f8955a5d7de9fab72fc8373fade9fb8a703968cb200ae3dc6cf08e185a" -dependencies = [ - "bytes", - "cfg_aliases", -] +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "buffa" -version = "0.7.1" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a92f2f5df67a9d5ccfc65237bfc954c56328aee40a04a9b92381ecba370be246" dependencies = [ "base64", "bytes", - "compact_str", - "ecow", + "foldhash", "hashbrown", "once_cell", + "rustversion", "serde", "serde_json", - "smol_str", + "smoothutf8", "thiserror", ] [[package]] name = "buffa-types" -version = "0.7.1" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15b05c8418f1e200e406e5b19df97400dffa833e2450e4392c506896cbc97ac" dependencies = [ "buffa", "bytes", + "jiff", "serde", "serde_json", "thiserror", @@ -52,48 +53,34 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" [[package]] -name = "castaway" -version = "0.2.4" +name = "defmt" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dec551ab6e7578819132c713a93c022a05d60159dc86e7a7050223577484c55a" +checksum = "e2953bfe4f93bbd20cc71198842756f77d161884c99ebbabc41d80231ded88d1" dependencies = [ - "rustversion", + "bitflags", + "defmt-macros", ] [[package]] -name = "cfg-if" -version = "1.0.4" +name = "defmt-macros" +version = "1.1.1" 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" +checksum = "bad9c72e7ca2137e0dc3813245a0d282fd6daad32fd800af018306a9169b5fe8" dependencies = [ - "castaway", - "cfg-if", - "itoa", - "rustversion", - "ryu", - "serde", - "static_assertions", + "defmt-parser", + "proc-macro2", + "quote", + "syn", ] [[package]] -name = "ecow" -version = "0.2.6" +name = "defmt-parser" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78e4f79b296fbaab6ce2e22d52cb4c7f010fe0ebe7a32e34fa25885fd797bd02" +checksum = "10d60334b3b2e7c9d91ef8150abfb6fa4c1c39ebbcf4a81c2e346aad939fee3e" dependencies = [ - "serde", + "thiserror", ] [[package]] @@ -128,6 +115,48 @@ version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" +[[package]] +name = "jiff" +version = "0.2.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "668b7183bd07af9a4885f5c35b0cc5c83c4607a913c16b7e17291832910d2dcc" +dependencies = [ + "defmt", + "jiff-core", + "jiff-static", + "log", + "portable-atomic", + "portable-atomic-util", + "serde_core", +] + +[[package]] +name = "jiff-core" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7feca88439efe53da3754500c1851dedf3cb36c524dd5cf8225cc0794de95d09" +dependencies = [ + "defmt", +] + +[[package]] +name = "jiff-static" +version = "0.2.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a69dcb3a21cfb32ce1cd056169337ca284af0766dd766e7878819b251a49204" +dependencies = [ + "jiff-core", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "log" +version = "0.4.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9f8bd3e56ce4dfc153cf470fffbfa98c7620958b312ca5c3a4b8d5181fd13c6" + [[package]] name = "memchr" version = "2.8.0" @@ -140,6 +169,21 @@ version = "1.21.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" +[[package]] +name = "portable-atomic" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05c8b63e8d9609db387f0324918f81d68fe27748f084ef092fb35954d0539a85" + +[[package]] +name = "portable-atomic-util" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10ab3eb7f3becc3a1cbc4f2c6f20267996cfc1a6467a873763411b136a122715" +dependencies = [ + "portable-atomic", +] + [[package]] name = "proc-macro2" version = "1.0.106" @@ -164,12 +208,6 @@ 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" @@ -214,20 +252,19 @@ dependencies = [ ] [[package]] -name = "smol_str" -version = "0.3.2" +name = "simdutf8" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9676b89cd56310a87b93dec47b11af744f34d5fc9f367b829474eec0a891350d" -dependencies = [ - "borsh", - "serde", -] +checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" [[package]] -name = "static_assertions" -version = "1.1.0" +name = "smoothutf8" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" +checksum = "6b4ec95892483d6d94284caccfddb9b77111a4dcac33ed25d624248def0fa5f1" +dependencies = [ + "simdutf8", +] [[package]] name = "syn" diff --git a/examples/bsr-quickstart/Cargo.toml b/examples/bsr-quickstart/Cargo.toml index 400b4a50..e0cba0fb 100644 --- a/examples/bsr-quickstart/Cargo.toml +++ b/examples/bsr-quickstart/Cargo.toml @@ -10,18 +10,12 @@ plugin with `file_per_package=true` and a hand-written `mod.rs`. See """ [dependencies] -# Path dependencies so the example builds against the in-tree workspace -# (consistent with the other `examples/*`). The checked-in `src/gen/` is -# generated by the *published* BSR plugin pinned in `buf.gen.yaml`, so this -# example also acts as a forward-compat canary: if an in-tree runtime change -# ever breaks code generated by the published plugin, this example fails to -# build. In a real downstream project, use crates.io versions instead: -# buffa = { version = "0.9", features = ["json"] } -# buffa-types = { version = "0.9", features = ["json"] } -# serde = { version = "1", features = ["derive"] } -# serde_json = "1" -buffa = { path = "../../buffa", features = ["json"] } -buffa-types = { path = "../../buffa-types", features = ["json"] } +# crates.io releases, not path dependencies: `src/gen/` is output from the +# published plugin pinned in `buf.gen.yaml`, which trails `main`, so it only +# compiles against the runtime from that same release. Keep these versions +# equal to that pin. In your own project, `version = "0.9"` is enough. +buffa = { version = "=0.9.2", features = ["json"] } +buffa-types = { version = "=0.9.2", features = ["json"] } serde = { version = "1", features = ["derive"] } serde_json = "1" diff --git a/examples/bsr-quickstart/buf.gen.yaml b/examples/bsr-quickstart/buf.gen.yaml index 98d4038e..63a711f5 100644 --- a/examples/bsr-quickstart/buf.gen.yaml +++ b/examples/bsr-quickstart/buf.gen.yaml @@ -9,13 +9,13 @@ # `protoc-gen-buffa-packaging` locally and add it as a second plugin (and # drop `file_per_package=true`). # -# The plugin reference is pinned to a specific version so the generated -# output is reproducible and a plugin update can't silently change it. Match -# the pin to the `buffa` runtime crate version in `Cargo.toml`. Bump it (and -# `task gen-bsr-quickstart-example`) when a new BSR plugin release ships. +# The plugin reference is pinned so the generated output is reproducible and a +# plugin update can't silently change it. `Cargo.toml` pins `buffa` / +# `buffa-types` to the same release: bump all three together, then run +# `task gen-bsr-quickstart-example`. version: v2 plugins: - - remote: buf.build/anthropics/buffa:v0.5.2 + - remote: buf.build/anthropics/buffa:v0.9.2 out: src/gen opt: - file_per_package=true diff --git a/examples/bsr-quickstart/src/gen/example.v1.rs b/examples/bsr-quickstart/src/gen/example.v1.rs index 8e3e6f2a..47f4b17e 100644 --- a/examples/bsr-quickstart/src/gen/example.v1.rs +++ b/examples/bsr-quickstart/src/gen/example.v1.rs @@ -161,7 +161,10 @@ pub struct Greeting { rename = "at", skip_serializing_if = "::buffa::json_helpers::skip_if::is_unset_message_field" )] - pub at: ::buffa::MessageField<::buffa_types::google::protobuf::Timestamp>, + pub at: ::buffa::MessageField< + ::buffa_types::google::protobuf::Timestamp, + ::buffa::Inline<::buffa_types::google::protobuf::Timestamp>, + >, /// The mood of the greeting. /// /// Field 3: `mood` @@ -204,12 +207,7 @@ impl Greeting { /// Format: `type.googleapis.com/` pub const TYPE_URL: &'static str = "type.googleapis.com/example.v1.Greeting"; } -impl ::buffa::DefaultInstance for Greeting { - fn default_instance() -> &'static Self { - static VALUE: ::buffa::__private::OnceBox = ::buffa::__private::OnceBox::new(); - VALUE.get_or_init(|| ::buffa::alloc::boxed::Box::new(Self::default())) - } -} +::buffa::impl_default_instance!(Greeting); impl ::buffa::MessageName for Greeting { const PACKAGE: &'static str = "example.v1"; const NAME: &'static str = "Greeting"; @@ -219,46 +217,48 @@ impl ::buffa::MessageName for Greeting { impl ::buffa::Message for Greeting { /// Returns the total encoded size in bytes. /// - /// The result is a `u32`; the protobuf specification requires all - /// messages to fit within 2 GiB (2,147,483,647 bytes), so a - /// compliant message will never overflow this type. + /// Accumulates in `u64` (which cannot overflow for in-memory + /// data) and saturates to `u32` at return, so a message whose + /// encoded size exceeds the 2 GiB protobuf limit yields a value + /// above [`::buffa::MAX_MESSAGE_BYTES`] that the encode entry + /// points reject, never a silently wrapped size. #[allow(clippy::let_and_return)] fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { #[allow(unused_imports)] use ::buffa::Enumeration as _; - let mut size = 0u32; + let mut size = 0u64; if !self.text.is_empty() { - size += 1u32 + ::buffa::types::string_encoded_len(&self.text) as u32; + size += 1u64 + ::buffa::types::string_encoded_len(&self.text) as u64; } if self.at.is_set() { let __slot = __cache.reserve(); let inner_size = self.at.compute_size(__cache); __cache.set(__slot, inner_size); size - += 1u32 + ::buffa::encoding::varint_len(inner_size as u64) as u32 - + inner_size; + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; } { let val = self.mood.to_i32(); if val != 0 { - size += 1u32 + ::buffa::types::int32_encoded_len(val) as u32; + size += 1u64 + ::buffa::types::int32_encoded_len(val) as u64; } } if let ::core::option::Option::Some(ref v) = self.recipient { match v { __buffa::oneof::greeting::Recipient::Name(x) => { - size += 1u32 + ::buffa::types::string_encoded_len(x) as u32; + size += 1u64 + ::buffa::types::string_encoded_len(x) as u64; } __buffa::oneof::greeting::Recipient::Everyone(_x) => { - size += 1u32 + ::buffa::types::BOOL_ENCODED_LEN as u32; + size += 1u64 + ::buffa::types::BOOL_ENCODED_LEN as u64; } } } for v in &self.tags { - size += 2u32 + ::buffa::types::string_encoded_len(v) as u32; + size += 2u64 + ::buffa::types::string_encoded_len(v) as u64; } - size += self.__buffa_unknown_fields.encoded_len() as u32; - size + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) } fn write_to( &self, @@ -268,57 +268,34 @@ impl ::buffa::Message for Greeting { #[allow(unused_imports)] use ::buffa::Enumeration as _; if !self.text.is_empty() { - ::buffa::encoding::Tag::new( - 1u32, - ::buffa::encoding::WireType::LengthDelimited, - ) - .encode(buf); - ::buffa::types::encode_string(&self.text, buf); + ::buffa::types::put_string_field(1u32, &self.text, buf); } if self.at.is_set() { - ::buffa::encoding::Tag::new( - 2u32, - ::buffa::encoding::WireType::LengthDelimited, - ) - .encode(buf); - ::buffa::encoding::encode_varint(__cache.consume_next() as u64, buf); + ::buffa::types::put_len_delimited_header( + 2u32, + u64::from(__cache.consume_next()), + buf, + ); self.at.write_to(__cache, buf); } { let val = self.mood.to_i32(); if val != 0 { - ::buffa::encoding::Tag::new(3u32, ::buffa::encoding::WireType::Varint) - .encode(buf); - ::buffa::types::encode_int32(val, buf); + ::buffa::types::put_int32_field(3u32, val, buf); } } if let ::core::option::Option::Some(ref v) = self.recipient { match v { __buffa::oneof::greeting::Recipient::Name(x) => { - ::buffa::encoding::Tag::new( - 10u32, - ::buffa::encoding::WireType::LengthDelimited, - ) - .encode(buf); - ::buffa::types::encode_string(x, buf); + ::buffa::types::put_string_field(10u32, x, buf); } __buffa::oneof::greeting::Recipient::Everyone(x) => { - ::buffa::encoding::Tag::new( - 11u32, - ::buffa::encoding::WireType::Varint, - ) - .encode(buf); - ::buffa::types::encode_bool(*x, buf); + ::buffa::types::put_bool_field(11u32, *x, buf); } } } for v in &self.tags { - ::buffa::encoding::Tag::new( - 20u32, - ::buffa::encoding::WireType::LengthDelimited, - ) - .encode(buf); - ::buffa::types::encode_string(v, buf); + ::buffa::types::put_string_field(20u32, v, buf); } self.__buffa_unknown_fields.write_to(buf); } @@ -334,23 +311,17 @@ impl ::buffa::Message for Greeting { use ::buffa::Enumeration as _; match tag.field_number() { 1u32 => { - if tag.wire_type() != ::buffa::encoding::WireType::LengthDelimited { - return ::core::result::Result::Err(::buffa::DecodeError::WireTypeMismatch { - field_number: 1u32, - expected: 2u8, - actual: tag.wire_type() as u8, - }); - } + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; ::buffa::types::merge_string(&mut self.text, buf)?; } 2u32 => { - if tag.wire_type() != ::buffa::encoding::WireType::LengthDelimited { - return ::core::result::Result::Err(::buffa::DecodeError::WireTypeMismatch { - field_number: 2u32, - expected: 2u8, - actual: tag.wire_type() as u8, - }); - } + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; ::buffa::Message::merge_length_delimited( self.at.get_or_insert_default(), buf, @@ -358,23 +329,17 @@ impl ::buffa::Message for Greeting { )?; } 3u32 => { - if tag.wire_type() != ::buffa::encoding::WireType::Varint { - return ::core::result::Result::Err(::buffa::DecodeError::WireTypeMismatch { - field_number: 3u32, - expected: 0u8, - actual: tag.wire_type() as u8, - }); - } + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; self.mood = ::buffa::EnumValue::from(::buffa::types::decode_int32(buf)?); } 10u32 => { - if tag.wire_type() != ::buffa::encoding::WireType::LengthDelimited { - return ::core::result::Result::Err(::buffa::DecodeError::WireTypeMismatch { - field_number: 10u32, - expected: 2u8, - actual: tag.wire_type() as u8, - }); - } + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; self.recipient = ::core::option::Option::Some( __buffa::oneof::greeting::Recipient::Name( ::buffa::types::decode_string(buf)?, @@ -382,13 +347,10 @@ impl ::buffa::Message for Greeting { ); } 11u32 => { - if tag.wire_type() != ::buffa::encoding::WireType::Varint { - return ::core::result::Result::Err(::buffa::DecodeError::WireTypeMismatch { - field_number: 11u32, - expected: 0u8, - actual: tag.wire_type() as u8, - }); - } + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; self.recipient = ::core::option::Option::Some( __buffa::oneof::greeting::Recipient::Everyone( ::buffa::types::decode_bool(buf)?, @@ -396,14 +358,15 @@ impl ::buffa::Message for Greeting { ); } 20u32 => { - if tag.wire_type() != ::buffa::encoding::WireType::LengthDelimited { - return ::core::result::Result::Err(::buffa::DecodeError::WireTypeMismatch { - field_number: 20u32, - expected: 2u8, - actual: tag.wire_type() as u8, - }); - } - self.tags.push(::buffa::types::decode_string(buf)?); + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + let __elem = ::buffa::types::decode_string(buf)?; + ctx.register_element_memory( + ::buffa::__private::element_footprint(&__elem), + )?; + self.tags.push(__elem); } _ => { self.__buffa_unknown_fields @@ -430,18 +393,21 @@ impl ::buffa::ExtensionSet for Greeting { &mut self.__buffa_unknown_fields } } -impl<'de> serde::Deserialize<'de> for Greeting { - fn deserialize>( +impl<'de> ::serde::Deserialize<'de> for Greeting { + fn deserialize>( d: D, ) -> ::core::result::Result { struct _V; - impl<'de> serde::de::Visitor<'de> for _V { + impl<'de> ::serde::de::Visitor<'de> for _V { type Value = Greeting; - fn expecting(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + fn expecting( + &self, + f: &mut ::core::fmt::Formatter<'_>, + ) -> ::core::fmt::Result { f.write_str("struct Greeting") } #[allow(clippy::field_reassign_with_default)] - fn visit_map>( + fn visit_map>( self, mut map: A, ) -> ::core::result::Result { @@ -449,7 +415,10 @@ impl<'de> serde::Deserialize<'de> for Greeting { ::buffa::alloc::string::String, > = None; let mut __f_at: ::core::option::Option< - ::buffa::MessageField<::buffa_types::google::protobuf::Timestamp>, + ::buffa::MessageField< + ::buffa_types::google::protobuf::Timestamp, + ::buffa::Inline<::buffa_types::google::protobuf::Timestamp>, + >, > = None; let mut __f_mood: ::core::option::Option<::buffa::EnumValue> = None; let mut __f_tags: ::core::option::Option< @@ -463,9 +432,9 @@ impl<'de> serde::Deserialize<'de> for Greeting { "text" => { __f_text = Some({ struct _S; - impl<'de> serde::de::DeserializeSeed<'de> for _S { + impl<'de> ::serde::de::DeserializeSeed<'de> for _S { type Value = ::buffa::alloc::string::String; - fn deserialize>( + fn deserialize>( self, d: D, ) -> ::core::result::Result< @@ -484,6 +453,7 @@ impl<'de> serde::Deserialize<'de> for Greeting { .next_value::< ::buffa::MessageField< ::buffa_types::google::protobuf::Timestamp, + ::buffa::Inline<::buffa_types::google::protobuf::Timestamp>, >, >()?, ); @@ -491,9 +461,9 @@ impl<'de> serde::Deserialize<'de> for Greeting { "mood" => { __f_mood = Some({ struct _S; - impl<'de> serde::de::DeserializeSeed<'de> for _S { + impl<'de> ::serde::de::DeserializeSeed<'de> for _S { type Value = ::buffa::EnumValue; - fn deserialize>( + fn deserialize>( self, d: D, ) -> ::core::result::Result< @@ -509,11 +479,11 @@ impl<'de> serde::Deserialize<'de> for Greeting { "tags" => { __f_tags = Some({ struct _S; - impl<'de> serde::de::DeserializeSeed<'de> for _S { + impl<'de> ::serde::de::DeserializeSeed<'de> for _S { type Value = ::buffa::alloc::vec::Vec< ::buffa::alloc::string::String, >; - fn deserialize>( + fn deserialize>( self, d: D, ) -> ::core::result::Result< @@ -540,7 +510,7 @@ impl<'de> serde::Deserialize<'de> for Greeting { if let Some(v) = v { if __oneof_recipient.is_some() { return Err( - serde::de::Error::custom( + ::serde::de::Error::custom( "multiple oneof fields set for 'recipient'", ), ); @@ -560,7 +530,7 @@ impl<'de> serde::Deserialize<'de> for Greeting { if let Some(v) = v { if __oneof_recipient.is_some() { return Err( - serde::de::Error::custom( + ::serde::de::Error::custom( "multiple oneof fields set for 'recipient'", ), ); @@ -571,7 +541,7 @@ impl<'de> serde::Deserialize<'de> for Greeting { } } _ => { - map.next_value::()?; + map.next_value::<::serde::de::IgnoredAny>()?; } } } @@ -666,151 +636,6 @@ pub mod __buffa { >, pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, } - impl<'a> GreetingView<'a> { - /// Decode from `buf` under the limits carried by `ctx` (recursion - /// depth and the shared unknown-field allowance). - /// - /// 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_ctx( - buf: &'a [u8], - ctx: ::buffa::DecodeContext<'_>, - ) -> ::core::result::Result { - let mut view = Self::default(); - view._merge_into_view(buf, ctx)?; - ::core::result::Result::Ok(view) - } - /// Merge fields from `buf` into this view (proto merge semantics). - /// - /// Repeated fields append; singular fields last-wins; singular - /// MESSAGE fields merge recursively. Used by sub-message decode - /// arms when the same field appears multiple times on the wire. - /// - /// **Not part of the public API.** - #[doc(hidden)] - pub fn _merge_into_view( - &mut self, - buf: &'a [u8], - ctx: ::buffa::DecodeContext<'_>, - ) -> ::core::result::Result<(), ::buffa::DecodeError> { - let _ = ctx; - #[allow(unused_variables)] - let view = self; - let mut cur: &'a [u8] = buf; - while !cur.is_empty() { - let before_tag = cur; - let tag = ::buffa::encoding::Tag::decode(&mut cur)?; - match tag.field_number() { - 1u32 => { - if tag.wire_type() - != ::buffa::encoding::WireType::LengthDelimited - { - return ::core::result::Result::Err(::buffa::DecodeError::WireTypeMismatch { - field_number: 1u32, - expected: 2u8, - actual: tag.wire_type() as u8, - }); - } - view.text = ::buffa::types::borrow_str(&mut cur)?; - } - 2u32 => { - if tag.wire_type() - != ::buffa::encoding::WireType::LengthDelimited - { - return ::core::result::Result::Err(::buffa::DecodeError::WireTypeMismatch { - field_number: 2u32, - expected: 2u8, - actual: tag.wire_type() as u8, - }); - } - 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, __sub_ctx)?, - None => { - view.at = ::buffa::MessageFieldView::set( - ::buffa_types::google::protobuf::__buffa::view::TimestampView::_decode_ctx( - sub, - __sub_ctx, - )?, - ); - } - } - } - 3u32 => { - if tag.wire_type() != ::buffa::encoding::WireType::Varint { - return ::core::result::Result::Err(::buffa::DecodeError::WireTypeMismatch { - field_number: 3u32, - expected: 0u8, - actual: tag.wire_type() as u8, - }); - } - view.mood = ::buffa::EnumValue::from( - ::buffa::types::decode_int32(&mut cur)?, - ); - } - 20u32 => { - if tag.wire_type() - != ::buffa::encoding::WireType::LengthDelimited - { - return ::core::result::Result::Err(::buffa::DecodeError::WireTypeMismatch { - field_number: 20u32, - expected: 2u8, - actual: tag.wire_type() as u8, - }); - } - view.tags.push(::buffa::types::borrow_str(&mut cur)?); - } - 10u32 => { - if tag.wire_type() - != ::buffa::encoding::WireType::LengthDelimited - { - return ::core::result::Result::Err(::buffa::DecodeError::WireTypeMismatch { - field_number: 10u32, - expected: 2u8, - actual: tag.wire_type() as u8, - }); - } - view.recipient = Some( - super::super::__buffa::view::oneof::greeting::Recipient::Name( - ::buffa::types::borrow_str(&mut cur)?, - ), - ); - } - 11u32 => { - if tag.wire_type() != ::buffa::encoding::WireType::Varint { - return ::core::result::Result::Err(::buffa::DecodeError::WireTypeMismatch { - field_number: 11u32, - expected: 0u8, - actual: tag.wire_type() as u8, - }); - } - view.recipient = Some( - super::super::__buffa::view::oneof::greeting::Recipient::Everyone( - ::buffa::types::decode_bool(&mut cur)?, - ), - ); - } - _ => { - ::buffa::encoding::skip_field_depth( - tag, - &mut cur, - ctx.depth(), - )?; - let span_len = before_tag.len() - cur.len(); - view.__buffa_unknown_fields - .push_record(before_tag, span_len, ctx)?; - } - } - } - ::core::result::Result::Ok(()) - } - } impl<'a> ::buffa::MessageView<'a> for GreetingView<'a> { type Owned = super::super::Greeting; fn decode_view( @@ -819,16 +644,116 @@ pub mod __buffa { let __limit = ::core::cell::Cell::new( ::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT, ); - Self::_decode_ctx( + let __elem = ::core::cell::Cell::new( + ::buffa::DEFAULT_ELEMENT_MEMORY_LIMIT, + ); + ::decode_view_ctx( buf, - ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit), + ::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit) + .with_element_memory(&__elem), ) } fn decode_view_with_ctx( buf: &'a [u8], ctx: ::buffa::DecodeContext<'_>, ) -> ::core::result::Result { - Self::_decode_ctx(buf, ctx) + ::decode_view_ctx(buf, ctx) + } + #[inline] + fn merge_view_field( + &mut self, + tag: ::buffa::encoding::Tag, + cur: &'a [u8], + before_tag: &'a [u8], + ctx: ::buffa::DecodeContext<'_>, + ) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> { + let _ = ctx; + #[allow(unused_variables)] + let view = self; + let mut cur = cur; + match tag.field_number() { + 1u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.text = ::buffa::types::borrow_str(&mut cur)?; + } + 2u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + let __sub_ctx = ctx.descend()?; + let sub = ::buffa::types::borrow_bytes(&mut cur)?; + match view.at.as_mut() { + Some(existing) => { + ::buffa::MessageView::merge_into_view( + existing, + sub, + __sub_ctx, + )? + } + None => { + view.at = ::buffa::MessageFieldView::set( + <::buffa_types::google::protobuf::__buffa::view::TimestampView as ::buffa::MessageView>::decode_view_ctx( + sub, + __sub_ctx, + )?, + ); + } + } + } + 3u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + view.mood = ::buffa::EnumValue::from( + ::buffa::types::decode_int32(&mut cur)?, + ); + } + 20u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + let __elem = ::buffa::types::borrow_str(&mut cur)?; + ctx.register_element_memory( + ::buffa::__private::element_footprint(&__elem), + )?; + view.tags.push(__elem); + } + 10u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::LengthDelimited, + )?; + view.recipient = Some( + super::super::__buffa::view::oneof::greeting::Recipient::Name( + ::buffa::types::borrow_str(&mut cur)?, + ), + ); + } + 11u32 => { + ::buffa::encoding::check_wire_type( + tag, + ::buffa::encoding::WireType::Varint, + )?; + view.recipient = Some( + super::super::__buffa::view::oneof::greeting::Recipient::Everyone( + ::buffa::types::decode_bool(&mut cur)?, + ), + ); + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields + .push_record(before_tag, span_len, ctx)?; + } + } + ::core::result::Result::Ok(cur) } fn to_owned_message( &self, @@ -849,6 +774,7 @@ pub mod __buffa { Some(v) => { ::buffa::MessageField::< ::buffa_types::google::protobuf::Timestamp, + ::buffa::Inline<::buffa_types::google::protobuf::Timestamp>, >::some(v.to_owned_from_source(__buffa_src)?) } None => ::buffa::MessageField::none(), @@ -887,22 +813,22 @@ pub mod __buffa { fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { #[allow(unused_imports)] use ::buffa::Enumeration as _; - let mut size = 0u32; + let mut size = 0u64; if !self.text.is_empty() { - size += 1u32 + ::buffa::types::string_encoded_len(&self.text) as u32; + size += 1u64 + ::buffa::types::string_encoded_len(&self.text) as u64; } if self.at.is_set() { let __slot = __cache.reserve(); let inner_size = self.at.compute_size(__cache); __cache.set(__slot, inner_size); size - += 1u32 + ::buffa::encoding::varint_len(inner_size as u64) as u32 - + inner_size; + += 1u64 + ::buffa::encoding::varint_len(inner_size as u64) as u64 + + inner_size as u64; } { let val = self.mood.to_i32(); if val != 0 { - size += 1u32 + ::buffa::types::int32_encoded_len(val) as u32; + size += 1u64 + ::buffa::types::int32_encoded_len(val) as u64; } } if let ::core::option::Option::Some(ref v) = self.recipient { @@ -910,20 +836,20 @@ pub mod __buffa { super::super::__buffa::view::oneof::greeting::Recipient::Name( x, ) => { - size += 1u32 + ::buffa::types::string_encoded_len(x) as u32; + size += 1u64 + ::buffa::types::string_encoded_len(x) as u64; } super::super::__buffa::view::oneof::greeting::Recipient::Everyone( _x, ) => { - size += 1u32 + ::buffa::types::BOOL_ENCODED_LEN as u32; + size += 1u64 + ::buffa::types::BOOL_ENCODED_LEN as u64; } } } for v in &self.tags { - size += 2u32 + ::buffa::types::string_encoded_len(v) as u32; + size += 2u64 + ::buffa::types::string_encoded_len(v) as u64; } - size += self.__buffa_unknown_fields.encoded_len() as u32; - size + size += self.__buffa_unknown_fields.encoded_len() as u64; + ::buffa::saturate_size(size) } #[allow(clippy::needless_borrow)] fn write_to( @@ -934,31 +860,20 @@ pub mod __buffa { #[allow(unused_imports)] use ::buffa::Enumeration as _; if !self.text.is_empty() { - ::buffa::encoding::Tag::new( - 1u32, - ::buffa::encoding::WireType::LengthDelimited, - ) - .encode(buf); - ::buffa::types::encode_string(&self.text, buf); + ::buffa::types::put_string_field(1u32, &self.text, buf); } if self.at.is_set() { - ::buffa::encoding::Tag::new( - 2u32, - ::buffa::encoding::WireType::LengthDelimited, - ) - .encode(buf); - ::buffa::encoding::encode_varint(__cache.consume_next() as u64, buf); + ::buffa::types::put_len_delimited_header( + 2u32, + u64::from(__cache.consume_next()), + buf, + ); self.at.write_to(__cache, buf); } { let val = self.mood.to_i32(); if val != 0 { - ::buffa::encoding::Tag::new( - 3u32, - ::buffa::encoding::WireType::Varint, - ) - .encode(buf); - ::buffa::types::encode_int32(val, buf); + ::buffa::types::put_int32_field(3u32, val, buf); } } if let ::core::option::Option::Some(ref v) = self.recipient { @@ -966,32 +881,17 @@ pub mod __buffa { super::super::__buffa::view::oneof::greeting::Recipient::Name( x, ) => { - ::buffa::encoding::Tag::new( - 10u32, - ::buffa::encoding::WireType::LengthDelimited, - ) - .encode(buf); - ::buffa::types::encode_string(x, buf); + ::buffa::types::put_string_field(10u32, x, buf); } super::super::__buffa::view::oneof::greeting::Recipient::Everyone( x, ) => { - ::buffa::encoding::Tag::new( - 11u32, - ::buffa::encoding::WireType::Varint, - ) - .encode(buf); - ::buffa::types::encode_bool(*x, buf); + ::buffa::types::put_bool_field(11u32, *x, buf); } } } for v in &self.tags { - ::buffa::encoding::Tag::new( - 20u32, - ::buffa::encoding::WireType::LengthDelimited, - ) - .encode(buf); - ::buffa::types::encode_string(v, buf); + ::buffa::types::put_string_field(20u32, v, buf); } self.__buffa_unknown_fields.write_to(buf); } @@ -1051,25 +951,8 @@ pub mod __buffa { 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 - Self: 'a, - { - static VALUE: ::buffa::__private::OnceBox> = ::buffa::__private::OnceBox::new(); - VALUE - .get_or_init(|| ::buffa::alloc::boxed::Box::new( - >::default(), - )) - } - } - impl ::buffa::ViewReborrow for GreetingView<'static> { - type Reborrowed<'b> = GreetingView<'b>; - fn reborrow<'b>(this: &'b Self) -> &'b Self::Reborrowed<'b> { - this - } - } - ::buffa::unsafe_impl_view_lifetime_parametric!(GreetingView); + ::buffa::impl_default_view_instance!(GreetingView); + ::buffa::impl_view_reborrow!(GreetingView); /** 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. @@ -1115,7 +998,9 @@ pub mod __buffa { /// /// # Errors /// - /// Returns [`::buffa::DecodeError`] if the re-encoded bytes are + /// Returns [`::buffa::DecodeError::MessageTooLarge`] if the + /// message's encoded size exceeds the 2 GiB protobuf limit, or + /// another [`::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, @@ -1131,13 +1016,13 @@ pub mod __buffa { } /// Convert to the owned message type. /// - /// # Errors - /// - /// Returns an error if re-materializing preserved unknown fields - /// fails (e.g. the unknown-field limit is exceeded). - pub fn to_owned_message( - &self, - ) -> ::core::result::Result { + /// Infallible: this type's constructors wire-decode their + /// buffer, and a view produced by wire decoding always + /// converts. Delegates to [`::buffa::OwnedView::to_owned_message`], + /// whose contract also governs handles converted from a raw + /// [`::buffa::OwnedView`]. + #[must_use] + pub fn to_owned_message(&self) -> super::super::Greeting { self.0.to_owned_message() } /// The underlying bytes buffer. @@ -1249,12 +1134,12 @@ pub mod __buffa { Everyone(bool), } impl ::buffa::Oneof for Recipient {} - impl serde::Serialize for Recipient { - fn serialize( + impl ::serde::Serialize for Recipient { + fn serialize( &self, s: S, ) -> ::core::result::Result { - use serde::ser::SerializeMap; + use ::serde::ser::SerializeMap; let mut map = s.serialize_map(Some(1))?; match self { Self::Name(v) => {