THIS IS NOT THE PLUGIN PUBLISHED ON CRATES.IO.
If you installed the plugin through cargo install protoc-gen-prost
, then the
plugin you installed is the one from https://github.com/neoeinstein/protoc-gen-prost.
This repository is kept for visibility and because some people depend on it.
A protoc
plugin to generate PROST! code.
While the recommended way to use prost
in Rust projects is with prost-build
and running protoc
through Cargo and build.rs
, a protoc plugin allows to
get a standard workflow in the protobuf ecosystem. Also, precompiling proto
files to Rust code as files has some advantages:
- easier to share compiled code across multiple projects, since they don't all need to setup the prost build
- rust code can be stored in an easy to browse fashion (git, ...)
- integrates well with standard protobuf/grpc/... tooling
- compatible with
buf
All usage examples assume protoc-gen-prost
was installed and can be found by
protoc
(i.e. in your $PATH
), and the output directory was created. The
example proto files can be found in this repository under proto/
.
protoc --prost_out=hello-rs -I proto types.proto
The proto file ends up compiled, as expected:
hello-rs/
└── helloworld.rs
And its compiled contents:
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct Message {
#[prost(string, tag = "1")]
pub say: ::prost::alloc::string::String,
}
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct Response {
#[prost(string, tag = "1")]
pub say: ::prost::alloc::string::String,
}
Options can be passed to the plugin through protoc
, using the --prost_opt
flag, separated with commas.
- Boolean options can just be specified
- Options taking a value are in the form
opt=value
- Options taking a key and a value are in the form
opt=key=value
- Commas can be escaped with
\
- Some options can be specified multiple times. Please refer to the option list below for a full reference.
- Some options have a default value
note: protoc-gen-prost
ignores whitespaces around commas to allow the opt
string to be spread on multiple lines
protoc \
-I proto \
--prost_out=hello-rs \
--prost_opt="
type_attribute=.helloworld.Message=#[derive(::serde::Serialize\, ::serde::Deserialize)],
type_attribute=.helloworld.Message=#[serde(rename_all = \"kebab-case\")],
field_attribute=.helloworld.Message.say=#[serde(rename = \"speak\")]" \
types.proto
The above sets two
type attributes
and a
field attribute
on a generated struct, and results in the following in hello-rs/helloworld.rs
:
#[derive(::serde::Serialize, ::serde::Deserialize)]
#[serde(rename_all = "kebab-case")]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct Message {
#[prost(string, tag = "1")]
#[serde(rename = "speak")]
pub say: ::prost::alloc::string::String,
}
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct Response {
#[prost(string, tag = "1")]
pub say: ::prost::alloc::string::String,
}
To ease usage and not need to include!
each and every generated file, the
include_file
option can be used. By default, it will generate a mod.rs
file
including all compiled Rust files, in a Rust module hierachy matching the proto
package hierarchy:
protoc -I proto --prost_out=hello-rs --prost_opt=include_file types.proto foo.proto
Results in the following hierarchy:
hello-rs/
├── helloworld.foo.bar.rs
├── helloworld.rs
└── mod.rs
... and with a complete include file:
pub mod helloworld {
include!(concat!("helloworld", ".rs"));
pub mod foo {
pub mod bar {
include!(concat!("helloworld.foo.bar", ".rs"));
}
}
}
The option can optionally take a file name to have it named something other than
mod.rs
:
protoc -I proto --prost_out=hello-rs --prost_opt=include_file=proto.rs \
types.proto foo.proto
For larger proto codebases, it is better to generate a full crate, or just to
shre the compiled results: it can be put in a crate and used as a direct Cargo
dependency, no fiddling with build.rs
or protoc
for the end-user.
Additionally, the generated crate will sport a feature flag for each proto package (with dependency resolution) to avoid slowing down build when only a few packages are used at once.
Its only requirement is a Cargo.toml
template to be put in the generated
crate. It is required to insert feature flags in it ({{ features }}
will get
replaced by all features):
[package]
name = "hello-rs"
version = "1.0.0"
edition = "2021"
[dependencies]
prost = "0.9"
prost-types = "0.9"
[features]
{{ features }}
As for input_file
, the gen_crate
argument takes an optional value,
defaulting to Cargo.toml.tpl
(path relative to protoc
's working directory'):
protoc -I proto \
--prost_out=hello-rs \
--prost_opt=gen_crate=hello-rs/Cargo.toml.tpl \
types.proto foo.proto
Results in the full crate:
hello-rs
├── Cargo.toml
├── Cargo.toml.tpl
├── gen
│ ├── helloworld.foo.bar.rs
│ └── helloworld.rs
└── src
└── lib.rs
with the following lib.rs
and Cargo.toml
:
pub mod helloworld {
#[cfg(feature = "helloworld")]
include!(concat!(env!("CARGO_MANIFEST_DIR"), "/gen/", "helloworld", ".rs"));
pub mod foo {
pub mod bar {
#[cfg(feature = "helloworld.foo.bar")]
include!(
concat!(env!("CARGO_MANIFEST_DIR"), "/gen/", "helloworld.foo.bar", ".rs")
);
}
}
}
[package]
name = "hello-grpc"
version = "1.0.0"
edition = "2021"
[dependencies]
prost = "0.9"
prost-types = "0.9"
[features]
"helloworld" = ["helloworld.foo.bar"]
"helloworld.foo.bar" = []
Please refer to
prost_build
's documentation
for a reference of each option, as those are 1:1 mappings.
btree_map=<value>
: repeatablebytes=<value>
: repeatablecompile_well_known_types
: booleandefault_package_filename=<value>
: stringdisable_comments=<value>
: repeatableextern_path=<key>=<value>
: repeatablefield_attribute=<key>=<value>
: repeatableretain_enum_prefix
: booleantype_attribute=<key>=<value>
: repeatable
include_file[=<value>]
: output a Rust file named<value>
that will include all generated.rs
files.- Defaults to
mod.rs
withoutgen_crate
, else tolib.rs
- Integrates with
gen_crate
: specifying the<value>
overrides the defaultlib.rs
name. This is useful if more code needs to be put in the generated crate.
- Defaults to
gen_crate[=<value>]
: generate a full-blown Rust crate with a manifest based on a template at<value>
, relative toprotoc
's working directory.- Defaults to
Cargo.toml.tpl
- Implies
include_file
set tolib.rs
if not already set
- Defaults to
file_descriptor_set[=<value>]
: output the protobufFileDescriptorSet
fromprotoc
. Used for plugins, reflection, ...- Defaults to
file_descriptor_set.rs
- It will contain a static
FILE_DESCRIPTOR_SET
variable containing a byte array of the serialized message.
- Defaults to
protoc-gen-prost
is compatible with e.g. Buf. Please note
that for the full crate generation (gen_crate
option) or include file
generation, the default buf strategy does not work, and requires the all
strategy for the include file to be complete.