Motivation
While spiking a buffa port for axum-extra's protobuf extractor, the main ergonomics gap relative to prost was the lack of an inline #[derive] for test and example code. prost users write:
#[derive(prost::Message)]
struct Input {
#[prost(string, tag = "1")]
foo: String,
}
directly inside #[cfg(test)] modules and doc examples. buffa is codegen-only, so the equivalent today is either:
- pull in
buffa-types and use a well-known type (StringValue, Int32Value) as a stand-in fixture, or
- add a
build.rs + .proto file just for tests.
The first works but reads oddly in docs ("where MyMessage is a type generated by protoc-gen-buffa…"); the second is heavyweight for a downstream crate that only wants one tiny test message.
This will recur on every downstream port (prometheus-client, pprof, libp2p-identity, etc.) — each has prost-derive test fixtures that need a buffa equivalent.
Proposal
A buffa-test-fixtures crate (or buffa-derive, name TBD) that provides a #[derive(buffa::Message)] proc-macro covering the minimal field set needed for tests and examples:
- scalar fields (
string, int32, int64, uint32, uint64, bool, bytes)
optional / repeated
- nested messages
- explicit
tag = N
Explicitly out of scope (to keep it from becoming a parallel production codegen path): maps, oneofs, enums, groups, extensions, editions feature resolution, view types, reflection, JSON/textproto. If a test needs those, it should use real codegen.
Positioning
The crate docs and README should be unambiguous that this is for tests and examples only — protoc-gen-buffa / buffa-build remain the supported path for production schemas. Something along the lines of:
This derive exists so downstream crates can write self-contained tests and doc examples without a build.rs. It supports a deliberately small subset of protobuf. For application code, generate types from .proto files.
A #[doc(hidden)] re-export from the main buffa crate behind a derive feature would let examples write #[derive(buffa::Message)] without a second dependency line, but that may invite production use — open to leaving it as a separate explicit dep instead.
Prior art
- prost's
prost-derive (the thing we're matching ergonomically)
serde's split between serde and serde_derive
Motivation
While spiking a buffa port for
axum-extra's protobuf extractor, the main ergonomics gap relative to prost was the lack of an inline#[derive]for test and example code. prost users write:directly inside
#[cfg(test)]modules and doc examples. buffa is codegen-only, so the equivalent today is either:buffa-typesand use a well-known type (StringValue,Int32Value) as a stand-in fixture, orbuild.rs+.protofile just for tests.The first works but reads oddly in docs ("where
MyMessageis a type generated byprotoc-gen-buffa…"); the second is heavyweight for a downstream crate that only wants one tiny test message.This will recur on every downstream port (prometheus-client, pprof, libp2p-identity, etc.) — each has prost-derive test fixtures that need a buffa equivalent.
Proposal
A
buffa-test-fixturescrate (orbuffa-derive, name TBD) that provides a#[derive(buffa::Message)]proc-macro covering the minimal field set needed for tests and examples:string,int32,int64,uint32,uint64,bool,bytes)optional/repeatedtag = NExplicitly out of scope (to keep it from becoming a parallel production codegen path): maps, oneofs, enums, groups, extensions, editions feature resolution, view types, reflection, JSON/textproto. If a test needs those, it should use real codegen.
Positioning
The crate docs and README should be unambiguous that this is for tests and examples only —
protoc-gen-buffa/buffa-buildremain the supported path for production schemas. Something along the lines of:A
#[doc(hidden)]re-export from the mainbuffacrate behind aderivefeature would let examples write#[derive(buffa::Message)]without a second dependency line, but that may invite production use — open to leaving it as a separate explicit dep instead.Prior art
prost-derive(the thing we're matching ergonomically)serde's split betweenserdeandserde_derive