All notable changes to buffa will be documented here.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning with the Rust 0.x convention: breaking changes increment the minor version (0.1 → 0.2), additive changes increment the patch version.
google.protobuf.Any.valueis now::bytes::Bytesinstead ofVec<u8>. MakesAny::clone()a cheap refcount bump (up to ~170x faster for large payloads) instead of a full memcpy. Call sites constructing anAnyby hand need.into()on the payload (e.g.value: my_vec.into(), or passBytesdirectly). Readingany.valueis unchanged —Bytesderefs to&[u8].buffa-typesnow depends onbytesunconditionally.
0.3.0 - 2026-04-01
Extension::new(number)→Extension::new(number, extendee). Same forExtension::with_default. Codegen consumers are unaffected — thepub constitems are regenerated. Hand-writtenExtensionconsts (unusual) need the extendee string added.ExtensionSettrait gained a requiredconst PROTO_FQN: &'static str. Codegen consumers are unaffected. Hand-written impls need the const added.extension(),set_extension(),clear_extension()now panic on extendee mismatch (previously: silently returnedNone/ no-op).has_extension()returnsfalsegracefully. Catchesfield_options.extension(&MESSAGE_OPTION)bugs at the first call site; matches protobuf-go (panics) and protobuf-es (throws).
set_any_registry,set_extension_registry— usebuffa::type_registry::set_type_registryinstead, which installs all maps in one call. The deprecated functions still work.AnyTypeEntry→JsonAnyEntry,ExtensionRegistryEntry→JsonExtEntry. Type aliases for one release cycle. The text-format fields have moved to separateTextAnyEntry/TextExtEntrystructs intype_registry.
- Full extension support.
Extension<C>typed descriptors,ExtensionSettrait withextension/set_extension/has_extension/clear_extension/extension_or_default, codec types for every proto field type (includingGroupCodecfor editionsDELIMITED/ proto2 groups), proto2[default = ...]on extension declarations, and MessageSet wire format behindCodeGenConfig::allow_message_set. See the Extensions section of the user guide. TypeRegistry— unified registry coveringAnytype entries and extension entries for both JSON and text formats. Codegen emitsregister_types(&mut TypeRegistry)per file; call once per generated file, thenset_type_registry(reg). JSON entries (JsonAnyEntry,JsonExtEntry) and text entries (TextAnyEntry,TextExtEntry) live in feature-split maps sojsonandtextare independently enableable.JsonParseOptions::strict_extension_keys— error on unregistered"[...]"JSON keys (default: silently drop, matching pre-0.3 behavior for all unknown keys).- Editions
features.message_encoding = DELIMITED— fully supported in codegen, previously parsed but ignored. Message fields with this feature use the group wire format (StartGroup/EndGroup) instead of length-prefixed. - Text format (
textproto) — thebuffa::textmodule providesTextFormattrait,TextEncoder,TextDecoder, andencode_to_string/decode_from_strconveniences. Enable withfeatures = ["text"](zero-dependency,no_std-compatible) andConfig::generate_text(true). CoversAnyexpansion ([type.googleapis.com/...] { ... }), extension brackets ([pkg.ext] { ... }), and group/DELIMITED naming.Anyexpansion and extension brackets consult the text maps inTypeRegistry— thejsonandtextfeatures are independently enableable. Passes the full text-format conformance suite (883/883). - Conformance:
TestAllTypesEdition2023enabled; binary+JSON 5539 → 5549 passing (std). Text format suite 0 → 883 passing (was entirely skipped). buffa-descriptorcrate —FileDescriptorProtoand friends are now in a standalone crate that depends only onbuffa, so descriptor types are usable without pulling inquote/syn/prettyplease.buffa-codegenre-exports the module so existingbuffa_codegen::generated::*paths still resolve. (#8)- Proto source comments → rustdoc. Comments from
.protofiles are now emitted as///doc comments on generated structs, fields, enums, variants, and view types. Requires--include_source_info(set automatically bybuffa-buildand the protoc plugins). (#7) buffa::encoding::MAX_FIELD_NUMBERconstant ((1 << 29) - 1), replacing the magic number at all call sites. (#21)
buffa-buildskips writing unchanged outputs, avoiding mtime bumps that trigger needless downstream recompilation. (#17)- Generated code emits
Selfinimplblocks instead of repeating the type name, so consumer crates that enableclippy::use_selfget clean output. (#15)
- Codegen no longer reports a false name collision between a nested type
and a proto3
optionalfield whose synthetic oneof PascalCases to the same name. (#20, fixes #12) - Generated rustdoc no longer breaks on proto comments containing
[foo][]reference-style links or bare URLs — these are now escaped so rustdoc treats them as literal text. (#25)
0.2.0 - 2026-03-16
-
protoc-gen-buffa: themod_file=<name>option is removed. Module tree assembly (mod.rsgeneration) is now a separate plugin,protoc-gen-buffa-packaging. The codegen plugin emits per-file.rsonly and no longer requiresstrategy: all.Migration - replace this:
plugins: - local: protoc-gen-buffa out: src/gen strategy: all opt: [mod_file=mod.rs]
with this:
plugins: - local: protoc-gen-buffa out: src/gen - local: protoc-gen-buffa-packaging out: src/gen strategy: all
Passing
mod_file=to the 0.2 plugin is a hard error with a migration hint (not a silent no-op).
-
protoc-gen-buffa-packaging- new protoc plugin that emits amod.rsmodule tree for per-file output. Works with any codegen plugin that follows buffa's per-file naming convention (foo/v1/bar.proto->foo.v1.bar.rs). Invoke once per output tree; compose via multiple buf.gen.yaml entries. Optionalfilter=servicesrestricts the tree to proto files that declare at least oneservice, for packaging service-stub-only output from plugins layered on buffa. Released as standalone binaries for the same five targets asprotoc-gen-buffa, with SLSA provenance and cosign signatures. -
buffa-codegen:"."accepted as a catch-allextern_pathprefix.extern_path = (".", "crate::proto")maps every proto package to an absolute Rust path rooted atcrate::proto. More-specific mappings (including the auto-injected WKT mapping) still win via longest-prefix-match.
buffa, buffa-types, buffa-codegen, and buffa-build have no breaking
API changes in this release. The version bump reflects the
protoc-gen-buffa CLI change; library consumers upgrading from 0.1 should
see no code changes required.
0.1.0 - 2026-03-07
Initial release.
| Feature | Status |
|---|---|
| Binary wire format (proto2, proto3, editions 2023/2024) | ✅ |
| Proto3 JSON canonical mapping | ✅ |
| Well-known types (Timestamp, Duration, Any, Struct, Value, FieldMask, wrappers) | ✅ |
| Unknown field preservation | ✅ (default on) |
| Zero-copy view types | ✅ |
Open enums (EnumValue<E>) with unknown-value preservation |
✅ |
| Closed enums (proto2) with unknown-value routing to unknown fields | ✅¹ |
| proto2 groups (singular, repeated, oneof) | ✅ |
proto2 custom defaults ([default = X]) |
✅ on required; optional stays None |
Editions feature resolution (field_presence, enum_type, repeated_field_encoding, utf8_validation) |
✅ |
Editions message_encoding = DELIMITED |
|
no_std + alloc (core runtime, views, JSON) |
✅ |
Text format (textproto) |
❌ Not planned |
| proto2 extensions | ❌ Not planned (use Any) |
| Runtime reflection | ❌ Not planned for 0.1 |
¹ See Known Limitations for two closed-enum edge cases (packed-repeated in views, map values).
Passes the protobuf conformance suite (v33.5):
- 5,539 passing binary + JSON tests (std)
- 5,519 passing binary + JSON tests (no_std — the 20-test gap is
IgnoreUnknownEnumStringValue*in repeated/map contexts, which requires scoped strict-mode override;no_stdhasset_global_json_parse_optionsfor singular-enum accept-with-default but not container filtering) - 2,797 passing via-view mode (binary →
decode_view→to_owned_message→ encode; direct JSON decode is not supported for views) - 0 expected failures across all three runs
- Text-format tests (883) are skipped (not supported)
- 94.3% line coverage (workspace, including build-script codegen paths)
- 1,018 unit tests across runtime, codegen, types, and integration
- 6 fuzz targets: binary decode (proto2, proto3, WKT), binary encode, JSON round-trip, WKT string parsers
- googleapis stress test: codegen compiles all ~3,000
.protofiles in the Google Cloud API set - protoc compatibility: plugin tested against protoc v21–v33
Comparison against prost 0.13 (lower = buffa faster):
| Operation | buffa vs prost |
|---|---|
| Binary encode | 0.56–0.74× (26–44% faster) |
| Binary decode | 0.91–1.29× (mixed; deep-nested messages slower) |
| JSON encode | 0.97–1.08× (parity) |
| JSON decode | 0.40–0.88× (12–60% faster) |
See the README Performance section for charts and raw data.
This release publishes:
buffa— core runtimebuffa-types— well-known types (Timestamp, Duration, Any, etc.)buffa-codegen— descriptor → Rust source (for downstream code generators)buffa-build—build.rsintegrationprotoc-gen-buffa— protoc plugin binary (also released as standalone binaries for linux-x86_64, linux-aarch64, darwin-x86_64, darwin-aarch64, windows-x86_64)
MSRV: Rust 1.85.