From ab92334ec3612374915ab29c6050dc28a45cb4c2 Mon Sep 17 00:00:00 2001 From: Iain McGinniss <309153+iainmcgin@users.noreply.github.com> Date: Thu, 7 May 2026 18:12:27 +0000 Subject: [PATCH 1/3] fix(buffa-codegen): use Self:: in oneof Serialize match arms MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The arms in generate_oneof_serialize live inside `impl Serialize for #enum_ident { fn serialize(&self, ..) { match self { .. } } }`, where `Self` resolves to the oneof enum. Using `#enum_ident::#ident` is spelled out the long way and trips rustc's clippy::use_self lint in workspaces that opt it on. The deserialize arms in oneof_variant_deser_arm are unchanged — those construct the oneof from inside the *message*'s Deserialize impl where `Self` would be wrong. --- buffa-codegen/src/oneof.rs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/buffa-codegen/src/oneof.rs b/buffa-codegen/src/oneof.rs index 165e6d9..9919f07 100644 --- a/buffa-codegen/src/oneof.rs +++ b/buffa-codegen/src/oneof.rs @@ -330,11 +330,18 @@ fn generate_oneof_serialize( let ident = &v.variant_ident; let json_name = &v.json_name; + // These arms live inside `impl Serialize for #enum_ident { fn + // serialize(&self, ..) { match self { .. } } }`, so `Self` + // resolves to the oneof enum and is the idiomatic spelling + // (rustc's `clippy::use_self` flags the qualified form). + // Contrast `oneof_variant_deser_arm` below, whose constructor + // calls run inside the *message*'s Deserialize impl where + // `Self` would be wrong. if v.is_null_value { // NullValue must serialize as JSON `null`, not "NULL_VALUE". // `&()` serializes as JSON `null` via serde_json. return quote! { - #enum_ident::#ident(_) => { + Self::#ident(_) => { map.serialize_entry(#json_name, &())?; } }; @@ -345,7 +352,7 @@ fn generate_oneof_serialize( // Type needs special proto JSON encoding — wrap in a newtype // that delegates to the helper's serialize function. quote! { - #enum_ident::#ident(v) => { + Self::#ident(v) => { struct _W<'a>(&'a #rust_type); impl serde::Serialize for _W<'_> { fn serialize(&self, s: S2) -> ::core::result::Result { @@ -357,7 +364,7 @@ fn generate_oneof_serialize( } } else { quote! { - #enum_ident::#ident(v) => { + Self::#ident(v) => { map.serialize_entry(#json_name, v)?; } } From 578164cc3fc25e41b1fa3e32fac2942c04add0d9 Mon Sep 17 00:00:00 2001 From: Iain McGinniss <309153+iainmcgin@users.noreply.github.com> Date: Thu, 7 May 2026 20:04:05 +0000 Subject: [PATCH 2/3] fix(buffa-codegen): inline format args in enum JSON deserialize errors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The enum visitor's range-check and unknown-value error messages used positional `{}` format args, which trips clippy::uninlined_format_args. Buffa's PackageMod stitcher only puts the ALLOW_LINTS `#[allow(...)]` on `__buffa`, so the per-proto Owned content (where these enum impls live) isn't covered by it — the lint reaches the surrounding mod's allow set, which not every wrapper carries. The inlined form is both lint-clean and the more idiomatic spelling; no semantic change. --- buffa-codegen/src/enumeration.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/buffa-codegen/src/enumeration.rs b/buffa-codegen/src/enumeration.rs index 3fffe14..a39d66d 100644 --- a/buffa-codegen/src/enumeration.rs +++ b/buffa-codegen/src/enumeration.rs @@ -43,12 +43,12 @@ fn generate_enum_serde(name_ident: &Ident) -> TokenStream { fn visit_i64(self, v: i64) -> ::core::result::Result<#name_ident, E> { let v32 = i32::try_from(v).map_err(|_| { ::serde::de::Error::custom( - ::buffa::alloc::format!("enum value {} out of i32 range", v) + ::buffa::alloc::format!("enum value {v} out of i32 range") ) })?; <#name_ident as ::buffa::Enumeration>::from_i32(v32).ok_or_else(|| { ::serde::de::Error::custom( - ::buffa::alloc::format!("unknown enum value {}", v32) + ::buffa::alloc::format!("unknown enum value {v32}") ) }) } @@ -56,12 +56,12 @@ fn generate_enum_serde(name_ident: &Ident) -> TokenStream { fn visit_u64(self, v: u64) -> ::core::result::Result<#name_ident, E> { let v32 = i32::try_from(v).map_err(|_| { ::serde::de::Error::custom( - ::buffa::alloc::format!("enum value {} out of i32 range", v) + ::buffa::alloc::format!("enum value {v} out of i32 range") ) })?; <#name_ident as ::buffa::Enumeration>::from_i32(v32).ok_or_else(|| { ::serde::de::Error::custom( - ::buffa::alloc::format!("unknown enum value {}", v32) + ::buffa::alloc::format!("unknown enum value {v32}") ) }) } From 0d705c65712d5aa4c0f9c63b7734f80ee651c562 Mon Sep 17 00:00:00 2001 From: Iain McGinniss <309153+iainmcgin@users.noreply.github.com> Date: Thu, 7 May 2026 21:54:56 +0000 Subject: [PATCH 3/3] chore: bump version to 0.5.2 --- CHANGELOG.md | 25 +++++++++++++++++++++++++ Cargo.lock | 16 ++++++++-------- Cargo.toml | 14 +++++++------- buffa-build/Cargo.toml | 2 +- buffa-codegen/Cargo.toml | 2 +- docs/guide.md | 20 ++++++++++---------- protoc-gen-buffa-packaging/Cargo.toml | 2 +- protoc-gen-buffa/Cargo.toml | 2 +- 8 files changed, 54 insertions(+), 29 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 43af069..09eb9b1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,31 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), ## [Unreleased] +## [0.5.2] - 2026-05-07 + +### Fixed + +- **`buffa-codegen`: oneof `Serialize` match arms now use `Self::#variant`.** + `generate_oneof_serialize` emits the manual JSON serde impl as + `impl Serialize for #enum_ident { fn serialize(&self, …) { match self { … } } }`, + where `Self` resolves to the oneof enum. The match arms used the + fully-qualified `#enum_ident::#variant` form, which trips + `clippy::use_self` in workspaces that opt it on — particularly visible + under `connectrpc-build`, which doesn't carry an inner `#![allow(...)]` + the way `protoc-gen-buffa-packaging` does, so the oneof companion file + inherits the surrounding mod's lint set. The deserialize arms in + `oneof_variant_deser_arm` remain qualified because they construct the + oneof from inside the *message*'s `Deserialize` impl, where `Self` would + be wrong. No behavioural change. +- **`buffa-codegen`: enum JSON deserialize errors use inlined format args.** + The enum visitor's range-check and unknown-value error messages used + positional `format!("enum value {} out of i32 range", v)` etc., which + trip `clippy::uninlined_format_args` for the same reason as above (the + enum impls live in the per-proto Owned content, outside the `__buffa` + `#[allow(...)]` block). Now `format!("enum value {v} out of i32 + range")` etc. — semantically identical, lint-clean regardless of which + module wrapper covers it. + ## [0.5.1] - 2026-05-07 ### Fixed diff --git a/Cargo.lock b/Cargo.lock index 2640db4..eb15e8e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -58,7 +58,7 @@ checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" [[package]] name = "buffa" -version = "0.5.1" +version = "0.5.2" dependencies = [ "arbitrary", "base64", @@ -72,7 +72,7 @@ dependencies = [ [[package]] name = "buffa-build" -version = "0.5.1" +version = "0.5.2" dependencies = [ "buffa", "buffa-codegen", @@ -81,7 +81,7 @@ dependencies = [ [[package]] name = "buffa-codegen" -version = "0.5.1" +version = "0.5.2" dependencies = [ "buffa", "buffa-descriptor", @@ -95,14 +95,14 @@ dependencies = [ [[package]] name = "buffa-descriptor" -version = "0.5.1" +version = "0.5.2" dependencies = [ "buffa", ] [[package]] name = "buffa-test" -version = "0.5.1" +version = "0.5.2" dependencies = [ "arbitrary", "buffa", @@ -115,7 +115,7 @@ dependencies = [ [[package]] name = "buffa-types" -version = "0.5.1" +version = "0.5.2" dependencies = [ "arbitrary", "buffa", @@ -520,7 +520,7 @@ dependencies = [ [[package]] name = "protoc-gen-buffa" -version = "0.5.1" +version = "0.5.2" dependencies = [ "buffa", "buffa-codegen", @@ -528,7 +528,7 @@ dependencies = [ [[package]] name = "protoc-gen-buffa-packaging" -version = "0.5.1" +version = "0.5.2" dependencies = [ "buffa", "buffa-codegen", diff --git a/Cargo.toml b/Cargo.toml index 8246224..5acb667 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,7 +24,7 @@ exclude = [ ] [workspace.package] -version = "0.5.1" +version = "0.5.2" edition = "2021" rust-version = "1.85" license = "Apache-2.0" @@ -33,12 +33,12 @@ keywords = ["protobuf", "protocol-buffers", "serialization", "no-std", "editions categories = ["encoding", "no-std"] [workspace.dependencies] -buffa = { path = "buffa", version = "0.5.1", default-features = false } -buffa-types = { path = "buffa-types", version = "0.5.1" } -buffa-descriptor = { path = "buffa-descriptor", version = "0.5.1" } -buffa-codegen = { path = "buffa-codegen", version = "0.5.1" } -buffa-build = { path = "buffa-build", version = "0.5.1" } -buffa-test = { path = "buffa-test", version = "0.5.1" } +buffa = { path = "buffa", version = "0.5.2", default-features = false } +buffa-types = { path = "buffa-types", version = "0.5.2" } +buffa-descriptor = { path = "buffa-descriptor", version = "0.5.2" } +buffa-codegen = { path = "buffa-codegen", version = "0.5.2" } +buffa-build = { path = "buffa-build", version = "0.5.2" } +buffa-test = { path = "buffa-test", version = "0.5.2" } base64 = { version = "0.22", default-features = false, features = ["alloc"] } bytes = { version = "1", default-features = false } hashbrown = { version = "0.15", default-features = false, features = ["default-hasher"] } diff --git a/buffa-build/Cargo.toml b/buffa-build/Cargo.toml index 1a1bc41..329d02f 100644 --- a/buffa-build/Cargo.toml +++ b/buffa-build/Cargo.toml @@ -13,6 +13,6 @@ categories = ["development-tools::build-utils"] rustdoc-args = ["--cfg", "docsrs"] [dependencies] -buffa = { path = "../buffa", version = "0.5.1" } +buffa = { path = "../buffa", version = "0.5.2" } buffa-codegen = { workspace = true } tempfile = "3" diff --git a/buffa-codegen/Cargo.toml b/buffa-codegen/Cargo.toml index 924f081..2ddd31e 100644 --- a/buffa-codegen/Cargo.toml +++ b/buffa-codegen/Cargo.toml @@ -11,7 +11,7 @@ categories = ["development-tools::build-utils"] [dependencies] # `path` wins for local workspace development; `version` is used on publish. -buffa = { path = "../buffa", version = "0.5.1" } +buffa = { path = "../buffa", version = "0.5.2" } buffa-descriptor = { workspace = true } prettyplease = { workspace = true } proc-macro2 = { workspace = true } diff --git a/docs/guide.md b/docs/guide.md index ee39c0b..abca78d 100644 --- a/docs/guide.md +++ b/docs/guide.md @@ -295,25 +295,25 @@ Download the binaries for your platform from the [releases page](https://github. ```sh # Download binaries + cosign signatures + certificates (both plugins match) -gh release download v0.5.1 --repo anthropics/buffa \ +gh release download v0.5.2 --repo anthropics/buffa \ --pattern 'protoc-gen-buffa*-linux-x86_64*' # Verify with GitHub attestations (requires gh CLI ≥ 2.49) -gh attestation verify protoc-gen-buffa-v0.5.1-linux-x86_64 --repo anthropics/buffa -gh attestation verify protoc-gen-buffa-packaging-v0.5.1-linux-x86_64 --repo anthropics/buffa +gh attestation verify protoc-gen-buffa-v0.5.2-linux-x86_64 --repo anthropics/buffa +gh attestation verify protoc-gen-buffa-packaging-v0.5.2-linux-x86_64 --repo anthropics/buffa # Or with cosign (standalone, no gh required) — shown for one binary cosign verify-blob \ - --signature protoc-gen-buffa-v0.5.1-linux-x86_64.sig \ - --certificate protoc-gen-buffa-v0.5.1-linux-x86_64.pem \ + --signature protoc-gen-buffa-v0.5.2-linux-x86_64.sig \ + --certificate protoc-gen-buffa-v0.5.2-linux-x86_64.pem \ --certificate-identity-regexp "github.com/anthropics/buffa" \ --certificate-oidc-issuer https://token.actions.githubusercontent.com \ - protoc-gen-buffa-v0.5.1-linux-x86_64 + protoc-gen-buffa-v0.5.2-linux-x86_64 # Install both -chmod +x protoc-gen-buffa-v0.5.1-linux-x86_64 protoc-gen-buffa-packaging-v0.5.1-linux-x86_64 -mv protoc-gen-buffa-v0.5.1-linux-x86_64 ~/.local/bin/protoc-gen-buffa -mv protoc-gen-buffa-packaging-v0.5.1-linux-x86_64 ~/.local/bin/protoc-gen-buffa-packaging +chmod +x protoc-gen-buffa-v0.5.2-linux-x86_64 protoc-gen-buffa-packaging-v0.5.2-linux-x86_64 +mv protoc-gen-buffa-v0.5.2-linux-x86_64 ~/.local/bin/protoc-gen-buffa +mv protoc-gen-buffa-packaging-v0.5.2-linux-x86_64 ~/.local/bin/protoc-gen-buffa-packaging ``` Available platforms: `linux-x86_64`, `linux-aarch64`, `darwin-x86_64`, `darwin-aarch64`, `windows-x86_64` (`.exe`). All releases include SHA-256 checksums, Sigstore cosign signatures, and signed SLSA build provenance for supply chain verification. @@ -369,7 +369,7 @@ Plugin options (passed via `opt:`): ```yaml version: v2 plugins: - - remote: buf.build/anthropic/buffa:v0.5.1 + - remote: buf.build/anthropic/buffa:v0.5.2 out: src/generated opt: [views=true] ``` diff --git a/protoc-gen-buffa-packaging/Cargo.toml b/protoc-gen-buffa-packaging/Cargo.toml index ce466bf..c05efb4 100644 --- a/protoc-gen-buffa-packaging/Cargo.toml +++ b/protoc-gen-buffa-packaging/Cargo.toml @@ -10,5 +10,5 @@ keywords = ["protobuf", "protocol-buffers", "protoc", "plugin", "codegen"] categories = ["development-tools::build-utils", "command-line-utilities"] [dependencies] -buffa = { path = "../buffa", version = "0.5.1" } +buffa = { path = "../buffa", version = "0.5.2" } buffa-codegen = { workspace = true } diff --git a/protoc-gen-buffa/Cargo.toml b/protoc-gen-buffa/Cargo.toml index 37313fa..8d7b115 100644 --- a/protoc-gen-buffa/Cargo.toml +++ b/protoc-gen-buffa/Cargo.toml @@ -10,5 +10,5 @@ keywords = ["protobuf", "protocol-buffers", "protoc", "plugin", "codegen"] categories = ["development-tools::build-utils", "command-line-utilities"] [dependencies] -buffa = { path = "../buffa", version = "0.5.1" } +buffa = { path = "../buffa", version = "0.5.2" } buffa-codegen = { workspace = true }