Skip to main content

CodeGenConfig

Struct CodeGenConfig 

Source
#[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
Non-exhaustive structs could have additional fields added in future. Therefore, non-exhaustive structs cannot be constructed in external crates using the traditional Struct { .. } syntax; cannot be matched against without a wildcard ..; and struct update syntax will not work.
§generate_views: bool

Whether to generate borrowed view types (MyMessageView<'a>) in addition to owned types.

§preserve_unknown_fields: bool

Whether to preserve unknown fields (default: true).

§generate_json: bool

Whether 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: bool

Whether 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: bool

Honor 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: bool

Permit 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: bool

Whether 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: bool

Whether 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-typesregister_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: bool

Emit 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: bool

Wrap 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: bool

Generate 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: bool

Generate 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-descriptor with the reflect feature.
  • std (the lazy pool accessor uses std::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.

Performancereflect() 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: bool

Emit 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: bool

Gate 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: bool

Emit 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_HIGHHigh), 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

Source§

fn clone(&self) -> CodeGenConfig

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for CodeGenConfig

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for CodeGenConfig

Source§

fn default() -> Self

Returns the “default value” for a type. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.