Expand description
Compile-time code generator for Protocol Buffer validation.
Generates impl prost_protovalidate::Validate for messages that have
only standard buf.validate rules (no CEL expressions). Validators
run through monomorphized direct field access at runtime — no
prost-reflect transcoding, no CEL interpreter on the hot path.
Messages with any CEL rules are, per builder configuration, skipped with
a cargo:warning (validate them with the runtime
prost_protovalidate::Validator), turned into a hard build error
(Builder::fail_on_runtime_only — a rule can never be silently
skipped), or, on the buffa backend, routed through an embedded runtime
engine (Builder::runtime_bridge) so the whole schema — CEL included —
validates through one uniform msg.validate().
§Backends
Generated code targets prost message
types by default. Select Backend::Buffa via Builder::backend
when the types were generated by
buffa (buffa-build, or a wrapper
such as connectrpc-build): presence checks go through
MessageField, enum accesses through EnumValue::to_i32, and type
paths keep verbatim proto names. Consumers pairing the buffa backend
with prost-protovalidate’s default-features = false get build-time
validation with no reflection or CEL in the runtime dependency graph.
§Usage
In your build.rs:
fn main() -> Result<(), Box<dyn std::error::Error>> {
// First, compile protos with prost-build (writes descriptor set)
let descriptor_path = std::path::PathBuf::from(std::env::var("OUT_DIR")?)
.join("file_descriptor_set.bin");
prost_build::Config::new()
.file_descriptor_set_path(&descriptor_path)
.compile_protos(&["proto/service.proto"], &["proto/"])?;
// Then generate validation impls
prost_protovalidate_build::Builder::new()
.file_descriptor_set_path(&descriptor_path)?
.compile()?;
Ok(())
}Then include the generated code alongside the prost-generated code:
include!(concat!(env!("OUT_DIR"), "/validate_impl.rs"));Structs§
- Builder
- Builder for configuring and running the validation code generator.