Generator

Struct Generator 

Source
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

Source

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.

Source

pub fn with_warning_callback(warning_cb: fn(Arguments<'_>)) -> Self

Create a generator with a custom callback for emitting warnings

Source

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)]"));
Source

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.

Source

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
Dot-separated Protobuf paths in config files MUST be wrapped in quotes for TOML parsing to work correctly.
Source

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.

Source

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.

Source

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.

Source

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.

Source

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();
Source

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.

Source

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.

Source

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.

Source

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.

Source

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.

Source

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.

Source

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.

Source

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.

Source

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.

Source

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.

Trait Implementations§

Source§

impl Debug for Generator

Source§

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

Formats the value using the given formatter. 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> 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, 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.