pub struct Generator { /* private fields */ }
Expand description
Protobuf code generator
Use this in build.rs
to compile .proto
files into a Rust module.
The main way to control the compilation process is to call configure
,
which allows the user to customize how code is generated from Protobuf types and fields of
their choosing.
§Note
It’s recommended to call one of use_container_alloc
,
use_container_heapless
, or
use_container_alloc
to ensure that container types are
configured for string
, bytes
, repeated, and map
fields. The generator will throw an
error if it reaches any such field that doesn’t have a container configured.
§Example
use micropb_gen::{Generator, Config};
let mut gen = Generator::new();
// Use container types from `heapless`
gen.use_container_heapless()
// Set max length of repeated fields in .test.Data to 4
.configure(".test.Data", Config::new().max_len(4))
// Wrap .test.Data.value inside a Box
.configure(".test.Data.value", Config::new().boxed(true))
// Compile test.proto into a Rust module
.compile_protos(
&["test.proto"],
std::env::var("OUT_DIR").unwrap() + "/test_proto.rs",
)
.unwrap();
Implementations§
Source§impl Generator
impl Generator
Sourcepub fn new() -> Self
pub fn new() -> Self
Create new generator with default settings
By default, the generator assumes it’s running inside a Cargo build script, so all warnings
will be emitted as compiler warnings. If the generator is not running inside a build
script, use with_warning_callback
.
Sourcepub fn with_warning_callback(warning_cb: fn(Arguments<'_>)) -> Self
pub fn with_warning_callback(warning_cb: fn(Arguments<'_>)) -> Self
Create a generator with a custom callback for emitting warnings
Sourcepub fn configure(&mut self, proto_path: &str, config: Config) -> &mut Self
pub fn configure(&mut self, proto_path: &str, config: Config) -> &mut Self
Apply code generator configurations to Protobuf types and fields. See
Config
for possible configuration options.
The proto_path
argument is a fully-qualified Protobuf path that points to a package,
type, or field in the compiled .proto
files. The configurations are applied to the
element specified by proto_path
, as well as its children.
§Example
// Configure field attributes on a specific field of a message type
gen.configure(".pkg.Message.int_field", Config::new().field_attributes("#[serde(skip)]"));
// Configure field attributes on all fields of a message type
gen.configure(".pkg.Message", Config::new().field_attributes("#[serde(skip)]"));
// Configure field attributes on all fields in a package
gen.configure(".pkg", Config::new().field_attributes("#[serde(skip)]"));
// Configure field attributes on all fields
gen.configure(".", Config::new().field_attributes("#[serde(skip)]"));
// Configure types attributes on a specific message type
gen.configure(".pkg.Message", Config::new().type_attributes("#[derive(Serialize)]"));
// Configure boxing behaviour on an oneof in a message type
gen.configure(".pkg.Message.my_oneof", Config::new().boxed(true));
// Configure the int size on a variant of an oneof
gen.configure(".pkg.Message.my_oneof_variant", Config::new().int_size(IntSize::S8));
// Configure the int size of an enum
// Note that enum variants cannot be configured
gen.configure(".pkg.Enum", Config::new().enum_int_size(IntSize::S8));
§Special paths
configure
also supports special path suffixes for configuring fields in the generated
code that don’t have a corresponding Protobuf path.
// Configure the int size of the elements in a repeated field via ".elem"
gen.configure(".pkg.Message.repeated_field.elem", Config::new().int_size(IntSize::S8));
// Configure the int size of the keys in a map field via ".key"
gen.configure(".pkg.Message.map_field.key", Config::new().int_size(IntSize::S8));
// Configure the int size of the values in a map field via ".value"
gen.configure(".pkg.Message.map_field.value", Config::new().int_size(IntSize::S16));
// Configure the field attributes of hazzer field and the type attributes of
// the hazzer struct in the message via "._has"
gen.configure(".pkg.Message._has",
Config::new().field_attributes("#[serde(skip)]").type_attributes("#[derive(Serialize)]"));
// Configure the field attributes for the unknown handler field of the message via "._unknown"
gen.configure(".pkg.Message._unknown", Config::new().field_attributes("#[serde(skip)]"));
Sourcepub fn configure_many(
&mut self,
proto_paths: &[&str],
config: Config,
) -> &mut Self
pub fn configure_many( &mut self, proto_paths: &[&str], config: Config, ) -> &mut Self
Apply one set of configurations to all provided Protobuf paths.
See configure
for how configurations are applied.
Sourcepub fn parse_config_file(
&mut self,
file_path: &Path,
package: &str,
) -> Result<(), Error>
pub fn parse_config_file( &mut self, file_path: &Path, package: &str, ) -> Result<(), Error>
Parse configurations from a TOML file and apply them to the specified Protobuf pacakge.
§Example
For example, if we have the following configuration in build.rs
:
let mut gen = micropb_gen::Generator::new();
gen.configure(
".my.pkg.Message.int_field",
Config::new().int_size(IntSize::S16).optional_repr(OptionalRepr::Option)
);
gen.configure("my.pkg.Message.bad_field", Config::new().skip(true));
We can instead load the configuration for .my.pkg
from a TOML file:
gen.parse_config_file(Path::new("my.pkg.toml"), ".my.pkg")?;
my.pkg.toml
# Each Config is represented as a table in the TOML document, keyed by the Protobuf path
["Message.int_field"]
int_size = "S16"
optional_repr = "Option"
["Message.bad_field"]
skip = true
Sourcepub fn use_container_heapless(&mut self) -> &mut Self
pub fn use_container_heapless(&mut self) -> &mut Self
Configure the generator to generate heapless
containers for Protobuf string
, bytes
,
repeated, and map
fields.
If using this option, micropb
should have the container-heapless
feature enabled.
Specifically, heapless::String<N>
is generated for string
fields, heapless::Vec<u8, N>
for bytes
fields, heapless::Vec<T, N>
for repeated fields, and
heapless::FnvIndexMap<K, V, N>
for map
fields. This uses configure
under the hood, so configurations set by this call can all be overriden.
§Note
Since heapless
containers are fixed size, max_len
or
max_bytes
must be set for all fields that generate these containers.
Sourcepub fn use_container_arrayvec(&mut self) -> &mut Self
pub fn use_container_arrayvec(&mut self) -> &mut Self
Configure the generator to generate arrayvec
containers for Protobuf string
, bytes
,
and repeated fields.
If using this option, micropb
should have the container-arrayvec
feature enabled.
Specifically, arrayvec::ArrayString<N>
is generated for string
fields,
arrayvec::ArrayVec<u8, N>
for bytes
fields, and arrayvec::ArrayVec<T, N>
for repeated
fields. This uses configure
under the hood, so configurations set by
this call can all be overriden.
§Note
No container is configured for map
fields, since arrayvec
doesn’t have a suitable map
type. If the .proto files contain map
fields, map_type
will need to
be configured separately.
Since arrayvec
containers are fixed size, max_len
or
max_bytes
must be set for all fields that generate these containers.
Sourcepub fn use_container_alloc(&mut self) -> &mut Self
pub fn use_container_alloc(&mut self) -> &mut Self
Configure the generator to generate alloc
containers for Protobuf string
, bytes
,
repeated, and map
fields.
If using this option, micropb
should have the alloc
feature enabled.
Specifically, alloc::string::String
is generated for string
fields,
alloc::vec::Vec<u8>
is for bytes
fields, alloc::vec::Vec<T>
for repeated fields, and
alloc::collections::BTreeMap<K, V>
for map
fields. This uses
configure
under the hood, so configurations set by this call can all
be overriden by future configurations.
Sourcepub fn use_container_std(&mut self) -> &mut Self
pub fn use_container_std(&mut self) -> &mut Self
Configure the generator to generate std
containers for Protobuf string
, bytes
,
repeated, and map
fields.
If using this option, micropb
should have the std
feature enabled.
Specifically, std::string::String
is generated for string
fields, std::vec::Vec<u8>
for bytes
fields, std::vec::Vec<T>
for repeated fields, and
std::collections::HashMap<K, V>
for map
fields. This uses
configure
under the hood, so configurations set by this call can all
be overriden by future configurations.
Sourcepub fn compile_protos(
&mut self,
protos: &[impl AsRef<Path>],
out_filename: impl AsRef<Path>,
) -> Result<()>
pub fn compile_protos( &mut self, protos: &[impl AsRef<Path>], out_filename: impl AsRef<Path>, ) -> Result<()>
Compile .proto
files into a single Rust file.
§Example
// build.rs
let mut gen = micropb_gen::Generator::new();
gen.compile_protos(&["server.proto", "client.proto"],
std::env::var("OUT_DIR").unwrap() + "/output.rs").unwrap();
Sourcepub fn compile_fdset_file(
&mut self,
fdset_file: impl AsRef<Path>,
out_filename: impl AsRef<Path>,
) -> Result<()>
pub fn compile_fdset_file( &mut self, fdset_file: impl AsRef<Path>, out_filename: impl AsRef<Path>, ) -> Result<()>
Compile a Protobuf file descriptor set into a Rust file.
Similar to compile_protos
, but it does not invoke protoc
and
instead takes a file descriptor set.
Sourcepub fn retain_enum_prefix(&mut self, retain_enum_prefix: bool) -> &mut Self
pub fn retain_enum_prefix(&mut self, retain_enum_prefix: bool) -> &mut Self
Determine whether the generator strips enum names from variant names.
Protobuf enums commonly include the enum name as a prefix of variant names. micropb
strips this enum name prefix by default. Setting this to true
prevents the prefix from
being stripped.
Sourcepub fn format(&mut self, format: bool) -> &mut Self
pub fn format(&mut self, format: bool) -> &mut Self
Determine whether the generator formats the output code.
If the format
feature isn’t enabled, this does nothing.
Sourcepub fn encode_decode(&mut self, encode_decode: EncodeDecode) -> &mut Self
pub fn encode_decode(&mut self, encode_decode: EncodeDecode) -> &mut Self
Determine whether to generate logic for encoding and decoding Protobuf messages.
Some applications don’t need to support both encoding and decoding. This setting allows either the encoding or decoding logic to be omitted from the output. By default, both encoding and decoding are included.
This setting allows omitting the encode
or decode
feature flag from micropb
.
Sourcepub fn file_descriptor_set_path<P: Into<PathBuf>>(
&mut self,
path: P,
) -> &mut Self
pub fn file_descriptor_set_path<P: Into<PathBuf>>( &mut self, path: P, ) -> &mut Self
When set, the file descriptor set generated by protoc
is written to the provided path,
instead of a temporary directory.
Sourcepub fn add_protoc_arg<S: AsRef<OsStr>>(&mut self, arg: S) -> &mut Self
pub fn add_protoc_arg<S: AsRef<OsStr>>(&mut self, arg: S) -> &mut Self
Add an argument to the protoc
invocation when compiling Protobuf files.
Sourcepub fn extern_type_path<P1: AsRef<str>, P2: AsRef<str>>(
&mut self,
proto_path: P1,
rust_path: P2,
) -> &mut Self
pub fn extern_type_path<P1: AsRef<str>, P2: AsRef<str>>( &mut self, proto_path: P1, rust_path: P2, ) -> &mut Self
Declare an externally-provided Protobuf type.
When compiling a .proto
file that imports types from another .proto
file, micropb
won’t compile the imported file if it’s not included in the
compile_protos
invocation. This is because the imported file may
have already been compiled in another crate. In order to recognize externally-imported
types, use extern_type_path
to map the full Protobuf path of the imported type to the
full path of the corresponding Rust type.
§Example
For example, let’s say we have app.proto
:
// app.proto
syntax = "proto3";
package app;
message App {
time.Timestamp timestamp = 1;
time.TZ timezone = 2;
}
app.proto
imports from time.proto
, which has already been compiled into the
time
crate:
// time.proto
syntax = "proto3";
package time;
message Timestamp {
uint32 ts = 1;
}
enum TZ {
TZ_UTC = 0;
TZ_PST = 1;
}
For our application, we’re only interested in compiling app.proto
, since time.proto
has
already been compiled by another crate. As such, we need to substitute Protobuf types
imported from time.proto
with Rust definitions from the time
crate.
// build.rs of app
let mut gen = micropb_gen::Generator::new();
// Substitute Timestamp message
gen.extern_type_path(".time.Timestamp", "time::Timestamp");
// Substitute TZ enum
gen.extern_type_path(".time.TZ", "time::Tz");
// Compile only app.proto, not time.proto
gen.compile_protos(&["app.proto"], std::env::var("OUT_DIR").unwrap() + "/output.rs").unwrap();
§Note
It’s technically possible to substitute in Rust types that aren’t generated by micropb-gen
.
However, the generated code expects substituted messages to implement MessageDecode
and
MessageEncode
, and substituted enums to have the “open-enum” structure.
Sourcepub fn calculate_max_size(&mut self, flag: bool) -> &mut Self
pub fn calculate_max_size(&mut self, flag: bool) -> &mut Self
Determines whether to generate code to calculate the MAX_SIZE
constant on each message.
By default, micropb-gen
generates code to calculate the MAX_SIZE
associated constant
for each message struct, which determines the max buffer size needed to encode it. If this
is set to false, then it replaces the calculations with None
, effectively disabling the
use of MAX_SIZE
. This has no runtime impact, but it can reduce the size of the output
file.
Sourcepub fn suffixed_package_names(&mut self, suffixed: bool) -> &mut Self
pub fn suffixed_package_names(&mut self, suffixed: bool) -> &mut Self
Determines whether the modules names generated from package specifiers are suffixed with an underscore.
This is on by default. Even when off, module names like “super” and modules created from from message names will still be suffixed.
Sourcepub fn single_oneof_msg_as_enum(&mut self, as_enum: bool) -> &mut Self
pub fn single_oneof_msg_as_enum(&mut self, as_enum: bool) -> &mut Self
For messages with only a single oneof and no other fields, generate an enum representing the oneof rather than a struct.
§Example
Given the following message:
message Number {
oneof inner {
sint32 signed = 1;
uint32 unsigned = 2;
float fraction = 3;
}
}
The following enum type will be generated:
pub enum Number {
Signed(i32),
Unsigned(u32),
Fraction(f32),
None,
}
All other message structures, including those with multiple oneofs or a single oneof plus normal fields, will be generated as normal message structs.
§Ignored configs
With this option, configurations that apply to the oneof itself (.Number.inner
) will be
ignored. Also, unknown_handler
will be ignored.