#[non_exhaustive]pub struct CodeGenConfig {Show 22 fields
pub generate_views: bool,
pub preserve_unknown_fields: bool,
pub generate_json: bool,
pub generate_arbitrary: bool,
pub extern_paths: Vec<(String, String)>,
pub bytes_fields: Vec<String>,
pub string_fields: Vec<(String, StringRepr)>,
pub strict_utf8_mapping: bool,
pub allow_message_set: bool,
pub generate_text: bool,
pub emit_register_fn: bool,
pub file_per_package: bool,
pub type_attributes: Vec<(String, String)>,
pub field_attributes: Vec<(String, String)>,
pub message_attributes: Vec<(String, String)>,
pub enum_attributes: Vec<(String, String)>,
pub gate_impls_on_crate_features: bool,
pub generate_with_setters: bool,
pub generate_reflection: bool,
pub generate_reflection_vtable: bool,
pub gate_reflect_on_crate_feature: bool,
pub idiomatic_enum_aliases: bool,
}Expand description
Configuration for code generation.
Fields (Non-exhaustive)§
This struct is marked as non-exhaustive
Struct { .. } syntax; cannot be matched against without a wildcard ..; and struct update syntax will not work.generate_views: boolWhether to generate borrowed view types (MyMessageView<'a>) in
addition to owned types.
preserve_unknown_fields: boolWhether to preserve unknown fields (default: true).
generate_json: boolWhether to derive serde::Serialize / serde::Deserialize on
generated message structs and enum types, and emit #[serde(with = "...")]
attributes for proto3 JSON’s special scalar encodings (int64 as quoted
string, bytes as base64, etc.).
When this is true, the downstream crate must depend on serde and
must enable the buffa/json feature for the runtime helpers.
Oneof fields use #[serde(flatten)] with custom Serialize /
Deserialize impls so that each variant appears as a top-level
JSON field (proto3 JSON inline oneof encoding).
generate_arbitrary: boolWhether to emit #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
on generated message structs and enum types.
When this is true, the downstream crate must add arbitrary as an
optional dependency and enable the buffa/arbitrary feature. The
downstream crate’s Cargo feature that gates arbitrary must be named
exactly "arbitrary" — the generated cfg_attr uses that literal
string and cannot be customized. This applies to both the struct-level
derive(Arbitrary) and the per-field #[arbitrary(with = ...)]
attributes emitted for bytes_fields-typed fields.
For bytes_fields-typed fields, codegen emits #[arbitrary(with = ...)]
using helpers in ::buffa::__private since bytes::Bytes has no
Arbitrary impl. Singular, optional, and repeated bytes fields are all
covered. Map values are always Vec<u8> regardless of bytes_fields
and require no special handling.
extern_paths: Vec<(String, String)>External type path mappings.
Each entry maps either a fully-qualified protobuf package prefix
(e.g., ".my.common") to a Rust module path (e.g.,
"::common_protos"), or a single type FQN (e.g.,
".my.common.Shared") to a full Rust type path (e.g.,
"::shared_types::Shared"). Matched types reference the extern Rust
path instead of being generated, allowing shared proto packages to be
compiled once in a dedicated crate and referenced from others. An
exact type-FQN entry wins over a covering package prefix; otherwise
the longest matching prefix wins.
Well-known types (google.protobuf.*) are automatically mapped to
::buffa_types::google::protobuf::* without needing an explicit
entry here. To override with a custom implementation, add an
extern_path for .google.protobuf pointing to your crate.
bytes_fields: Vec<String>Fully-qualified proto field paths whose bytes fields should use
bytes::Bytes instead of Vec<u8>.
Each entry is a proto path prefix (e.g., ".my.pkg.MyMessage.data" for
a specific field, or "." for all bytes fields). The path is matched
as a prefix, so "." applies to every bytes field in every message.
string_fields: Vec<(String, StringRepr)>Ordered (proto-path-prefix, StringRepr) rules selecting the Rust type
for string fields. Later rules win, so a broad rule (e.g. "." →
SmolStr) can be refined by a more specific one
(".my.pkg.Msg.field" → CompactString). Fields matching no rule use
String. The path is matched with the same proto-segment-aware prefix
logic as bytes_fields.
Applies to singular, optional, and repeated string fields and oneof
string variants. Map keys and values always stay String, mirroring
the bytes path (where map values always stay Vec<u8>).
strict_utf8_mapping: boolHonor features.utf8_validation = NONE by emitting Vec<u8> / &[u8]
for such string fields instead of String / &str.
When false (the default), buffa emits String for all string fields
and validates UTF-8 on decode — stricter than proto2 requires, but
ergonomic and safe.
When true, string fields with utf8_validation = NONE (all proto2
strings by default, and editions fields that opt into NONE) become
Vec<u8> / &[u8]. Decode skips validation; the caller decides at the
call site whether to std::str::from_utf8 (checked) or
from_utf8_unchecked (trusted-input fast path). This is the only
sound Rust mapping when strings may actually contain non-UTF-8 bytes.
This is a breaking change for proto2 — enable only for new code or when profiling identifies UTF-8 validation as a bottleneck.
allow_message_set: boolPermit option message_set_wire_format = true on input messages.
MessageSet is a legacy Google-internal wire format that wraps each
extension in a group structure instead of using regular field tags.
When false (the default), encountering such a message is a codegen
error — the flag exists to make MessageSet use explicit, since the
format is obsolete outside of interop with very old Google protos.
generate_text: boolWhether to emit impl buffa::text::TextFormat on generated message
structs for textproto (human-readable text format) encoding/decoding.
When this is true, the downstream crate must enable the buffa/text
feature for the runtime encoder/decoder.
emit_register_fn: boolWhether the per-package .mod.rs stitcher emits
__buffa::register_types(&mut TypeRegistry).
Default true. The fn aggregates Any type entries and extension
entries for every message in the package. Set to false for
crates that don’t use extensions/Any, or that hand-roll
registration (e.g. buffa-types’ register_wkt_types, which
knows the JSON-Any is_wkt special-casing the generic fn does
not). The per-message __*_JSON_ANY / __*_TEXT_ANY consts are
still emitted; only the aggregating fn is suppressed.
file_per_package: boolEmit one <dotted.package>.rs per proto package instead of the
per-proto-file content set plus <pkg>.mod.rs stitcher.
The single file inlines what the stitcher would otherwise include!,
producing the same __buffa::{view,oneof,ext,...} module structure.
Intended for Buf Schema Registry generated SDKs, whose lib.rs
synthesis builds the module tree from <dotted.package>.rs filenames.
Under strategy: directory this only sees one directory’s files per
invocation, so the input module must be PACKAGE_DIRECTORY_MATCH-clean
(one package per directory) for the output to be complete. BSR-hosted
modules satisfy this by lint default. If a package spans multiple
directories, separate invocations each emit their own <pkg>.rs and
the last write wins — silent partial output, not a codegen error.
type_attributes: Vec<(String, String)>Custom attributes to inject on generated types (messages and enums).
Each entry is (proto_path, attribute). The proto_path is matched
as a prefix against the fully-qualified proto name: "." applies to
all types, ".my.pkg" to types in that package, ".my.pkg.MyMessage"
to a specific type. The attribute is a raw Rust attribute string
(e.g., "#[derive(serde::Serialize)]").
field_attributes: Vec<(String, String)>Custom attributes to inject on generated struct fields.
Each entry is (proto_path, attribute). The proto_path is matched
as a prefix against the fully-qualified field path (e.g.,
".my.pkg.MyMessage.my_field"). "." applies to all fields.
message_attributes: Vec<(String, String)>Custom attributes to inject on generated message structs only (not enums).
Same path-matching semantics as type_attributes, but only applied to
message structs, not enum types. Useful for struct-only attributes like
#[serde(default)].
enum_attributes: Vec<(String, String)>Custom attributes to inject on generated enum types only (not messages).
Same path-matching semantics as type_attributes, but only applied to
enum types. Useful for enum-only attributes like
#[derive(strum::EnumIter)] when the user does not want to apply the
same attribute to every message in the matched scope.
gate_impls_on_crate_features: boolWrap generated impls in #[cfg(feature = "...")] instead of
emitting them unconditionally.
When true, the impls controlled by generate_json,
generate_views, and generate_text are emitted wrapped in
#[cfg(feature = "json" | "views" | "text")] (or
#[cfg_attr(feature = ..., ...)] for derives and field attributes)
rather than unconditionally. The consuming crate must define matching
Cargo features that enable the corresponding runtime support, e.g.:
[features]
json = ["buffa/json", "dep:serde", "dep:serde_json"]
views = []
text = ["buffa/text"]The generate_* flags still control whether an impl kind is
emitted at all — this flag only controls whether it is cfg-gated.
generate_arbitrary is always cfg_attr-gated on
feature = "arbitrary" regardless of this flag, because arbitrary
is an optional dependency by design.
When generate_reflection is also on, the
reflection impls are gated on feature = "reflect" alongside
json/views/text. To gate only reflection without gating json/views/text,
use gate_reflect_on_crate_feature
instead.
This is the mechanism that lets buffa-descriptor and buffa-types
ship every impl while keeping the codegen toolchain
(buffa-codegen/buffa-build/protoc-gen-buffa) lean: those crates
depend on buffa-descriptor with default-features = false and so
don’t pull serde/serde_json/base64. Most consumers don’t need
this — they decide at build-script time whether to generate JSON, and
if they say yes, they want impl Serialize to just exist.
generate_with_setters: boolGenerate with_* builder-style setter methods for explicit-presence fields.
Each explicit-presence scalar, bytes, or enum field gets a
pub fn with_<name>(mut self, value: T) -> Self method that wraps the
value in Some and returns self, enabling chained construction:
let req = MyRequest::default()
.with_name("alice")
.with_timeout_ms(30_000);Fields that receive a setter: proto3 optional, proto2 optional,
and editions fields with field_presence = EXPLICIT.
Fields that do not receive a setter: message fields
(MessageField<T>), repeated fields, map fields, oneof variant fields,
proto2 required fields, and any implicit-presence field.
There is no clear_<name> companion — to clear a field, assign None
directly: msg.name = None;.
Defaults to true.
generate_reflection: boolGenerate impl Reflectable for owned message types (bridge mode).
When enabled, each generated message gets an
impl ::buffa_descriptor::reflect::Reflectable whose reflect()
round-trips through DynamicMessage (encode → decode → reflective
handle), and the package’s __buffa::reflect submodule embeds the
FileDescriptorSet bytes plus a lazily-built DescriptorPool.
Runtime requirements — the consuming crate must depend on:
buffa-descriptorwith thereflectfeature.std(the lazy pool accessor usesstd::sync::OnceLock).
When gate_impls_on_crate_features
is on, the impls are wrapped in #[cfg(feature = "reflect")] so the
consuming crate can opt out per build.
Performance — reflect() is one full encode/decode round-trip
plus a heap allocation. The first call also pays a one-time pool
build cost (linking the embedded FileDescriptorSet). For zero-copy
reflective access over view types without the round-trip, additionally
enable generate_reflection_vtable.
Binary size — each package embeds its own copy of the full
FileDescriptorSet (transitive closure). For a multi-package
codegen run this duplicates the FDS bytes per package. Acceptable
for the bridge prototype; deduplication via a crate-root module is
a planned follow-up.
Defaults to false.
generate_reflection_vtable: boolEmit vtable-mode reflection: impl ReflectMessage / impl ReflectElement on the owned message structs and (when views are
generated) the view types, and switch the owned
Reflectable::reflect() body to borrow self
(ReflectCow::Borrowed(self)) instead of the bridge round-trip.
Reflective access then reads struct fields in place — no encode/decode round-trip and no per-field allocation — for both a decoded view and an in-memory owned message.
Requires generate_reflection (the impls
resolve against the same embedded DescriptorPool) but not
generate_views — with views off, only the
owned impls are emitted. Set via ReflectMode::VTable
— front-ends expose it as buffa_build::Config::reflect_mode /
protoc-gen-buffa’s reflect_mode=vtable.
Defaults to false.
gate_reflect_on_crate_feature: boolGate the reflection impls behind a reflect crate feature, without
gating json/views/text (unlike
gate_impls_on_crate_features,
which gates them all together).
Used by crates that ship view/text impls unconditionally but want the
reflection surface — which pulls a buffa-descriptor dependency and
std — to be opt-in. buffa-types is the motivating case: its WKT
views are always available, but impl ReflectMessage for them is gated
behind buffa-types’s reflect feature.
When gate_impls_on_crate_features
is already on, reflection is gated regardless and this flag is ignored.
A low-level knob for crates whose generated code is a public interface
(buffa-types, the conformance harness). Set directly by gen_wkt_types
and exposed through buffa_build::Config::gate_reflect_on_crate_feature
(currently #[doc(hidden)], paired with the experimental vtable flag).
Defaults to false.
idiomatic_enum_aliases: boolEmit idiomatic UpperCamelCase constant aliases alongside each enum
variant.
Protobuf style names enum values in SHOUTY_SNAKE_CASE, conventionally
prefixed with the enum name (RULE_LEVEL_HIGH). Those names remain the
definitive Rust variants — they are guaranteed unique and valid by
protobuf, and existing references (including Debug output) are
unchanged. When this is enabled, codegen additionally emits associated
consts with the prefix stripped and the name converted to
UpperCamelCase (RULE_LEVEL_HIGH → High), so downstream code can
write RuleLevel::High.
The conversion is lossy, so two values can collide (FOO_BAR and
FOO__BAR both map to FooBar). The rule is all-or-nothing per enum:
if any two values would collide after conversion, or a value would yield
an invalid identifier, no aliases are emitted for that enum (a
CodeGenWarning and an enum doc note explain why). This keeps every
match either fully SHOUTY_SNAKE_CASE or fully idiomatic, never a forced
mix.
The aliases are associated consts, which work in pattern position too:
a match written entirely against aliases is still exhaustiveness-checked
(the “non-exhaustive” error names the underlying SHOUTY_SNAKE_CASE
variant, since that is the canonical name).
Defaults to true: the aliases are purely additive (the proto names
remain the variants, and Debug is unchanged), so enabling by default is
backward-compatible, and the all-or-nothing rule guarantees correctness on
any enum.
Trait Implementations§
Source§impl Clone for CodeGenConfig
impl Clone for CodeGenConfig
Source§fn clone(&self) -> CodeGenConfig
fn clone(&self) -> CodeGenConfig
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read more