Struct prost_build::Config

source ·
pub struct Config { /* private fields */ }
Expand description

Configuration options for Protobuf code generation.

This configuration builder can be used to set non-default code generation options.

Implementations§

Creates a new code generator configuration with default options.

Examples found in repository?
src/lib.rs (line 1267)
1266
1267
1268
pub fn compile_protos(protos: &[impl AsRef<Path>], includes: &[impl AsRef<Path>]) -> Result<()> {
    Config::new().compile_protos(protos, includes)
}

Configure the code generator to generate Rust BTreeMap fields for Protobuf map type fields.

Arguments

paths - paths to specific fields, messages, or packages which should use a Rust BTreeMap for Protobuf map fields. Paths are specified in terms of the Protobuf type name (not the generated Rust type name). Paths with a leading . are treated as fully qualified names. Paths without a leading . are treated as relative, and are suffix matched on the fully qualified field name. If a Protobuf map field matches any of the paths, a Rust BTreeMap field is generated instead of the default HashMap.

The matching is done on the Protobuf names, before converting to Rust-friendly casing standards.

Examples
// Match a specific field in a message type.
config.btree_map(&[".my_messages.MyMessageType.my_map_field"]);

// Match all map fields in a message type.
config.btree_map(&[".my_messages.MyMessageType"]);

// Match all map fields in a package.
config.btree_map(&[".my_messages"]);

// Match all map fields. Specially useful in `no_std` contexts.
config.btree_map(&["."]);

// Match all map fields in a nested message.
config.btree_map(&[".my_messages.MyMessageType.MyNestedMessageType"]);

// Match all fields named 'my_map_field'.
config.btree_map(&["my_map_field"]);

// Match all fields named 'my_map_field' in messages named 'MyMessageType', regardless of
// package or nesting.
config.btree_map(&["MyMessageType.my_map_field"]);

// Match all fields named 'my_map_field', and all fields in the 'foo.bar' package.
config.btree_map(&["my_map_field", ".foo.bar"]);

Configure the code generator to generate Rust bytes::Bytes fields for Protobuf bytes type fields.

Arguments

paths - paths to specific fields, messages, or packages which should use a Rust Bytes for Protobuf bytes fields. Paths are specified in terms of the Protobuf type name (not the generated Rust type name). Paths with a leading . are treated as fully qualified names. Paths without a leading . are treated as relative, and are suffix matched on the fully qualified field name. If a Protobuf map field matches any of the paths, a Rust Bytes field is generated instead of the default Vec<u8>.

The matching is done on the Protobuf names, before converting to Rust-friendly casing standards.

Examples
// Match a specific field in a message type.
config.bytes(&[".my_messages.MyMessageType.my_bytes_field"]);

// Match all bytes fields in a message type.
config.bytes(&[".my_messages.MyMessageType"]);

// Match all bytes fields in a package.
config.bytes(&[".my_messages"]);

// Match all bytes fields. Specially useful in `no_std` contexts.
config.bytes(&["."]);

// Match all bytes fields in a nested message.
config.bytes(&[".my_messages.MyMessageType.MyNestedMessageType"]);

// Match all fields named 'my_bytes_field'.
config.bytes(&["my_bytes_field"]);

// Match all fields named 'my_bytes_field' in messages named 'MyMessageType', regardless of
// package or nesting.
config.bytes(&["MyMessageType.my_bytes_field"]);

// Match all fields named 'my_bytes_field', and all fields in the 'foo.bar' package.
config.bytes(&["my_bytes_field", ".foo.bar"]);

Add additional attribute to matched fields.

Arguments

path - a path matching any number of fields. These fields get the attribute. For details about matching fields see btree_map.

attribute - an arbitrary string that’ll be placed before each matched field. The expected usage are additional attributes, usually in concert with whole-type attributes set with type_attribute, but it is not checked and anything can be put there.

Note that the calls to this method are cumulative ‒ if multiple paths from multiple calls match the same field, the field gets all the corresponding attributes.

Examples
// Prost renames fields named `in` to `in_`. But if serialized through serde,
// they should as `in`.
config.field_attribute("in", "#[serde(rename = \"in\")]");

Add additional attribute to matched messages, enums and one-ofs.

Arguments

paths - a path matching any number of types. It works the same way as in btree_map, just with the field name omitted.

attribute - an arbitrary string to be placed before each matched type. The expected usage are additional attributes, but anything is allowed.

The calls to this method are cumulative. They don’t overwrite previous calls and if a type is matched by multiple calls of the method, all relevant attributes are added to it.

For things like serde it might be needed to combine with field attributes.

Examples
// Nothing around uses floats, so we can derive real `Eq` in addition to `PartialEq`.
config.type_attribute(".", "#[derive(Eq)]");
// Some messages want to be serializable with serde as well.
config.type_attribute("my_messages.MyMessageType",
                      "#[derive(Serialize)] #[serde(rename_all = \"snake_case\")]");
config.type_attribute("my_messages.MyMessageType.MyNestedMessageType",
                      "#[derive(Serialize)] #[serde(rename_all = \"snake_case\")]");
Oneof fields

The oneof fields don’t have a type name of their own inside Protobuf. Therefore, the field name can be used both with type_attribute and field_attribute ‒ the first is placed before the enum type definition, the other before the field inside corresponding message struct.

In other words, to place an attribute on the enum implementing the oneof, the match would look like my_messages.MyMessageType.oneofname.

Configures the code generator to use the provided service generator.

Configures the code generator to not use the prost_types crate for Protobuf well-known types, and instead generate Protobuf well-known types from their .proto definitions.

Configures the code generator to omit documentation comments on generated Protobuf types.

Example

Occasionally .proto files contain code blocks which are not valid Rust. To avoid doctest failures, annotate the invalid code blocks with an ignore or no_run attribute, or disable doctests for the crate with a Cargo.toml entry. If neither of these options are possible, then omit comments on generated code during doctest builds:

let mut config = prost_build::Config::new();
config.disable_comments(&["."]);
config.compile_protos(&["src/frontend.proto", "src/backend.proto"], &["src"])?;

As with other options which take a set of paths, comments can be disabled on a per-package or per-symbol basis.

Declare an externally provided Protobuf package or type.

extern_path allows prost types in external crates to be referenced in generated code.

When prost compiles a .proto which includes an import of another .proto, it will automatically recursively compile the imported file as well. extern_path can be used to instead substitute types from an external crate.

Example

As an example, consider a crate, uuid, with a prost-generated Uuid type:

// uuid.proto

syntax = "proto3";
package uuid;

message Uuid {
    string uuid_str = 1;
}

The uuid crate implements some traits for Uuid, and publicly exports it:

// lib.rs in the uuid crate

include!(concat!(env!("OUT_DIR"), "/uuid.rs"));

pub trait DoSomething {
    fn do_it(&self);
}

impl DoSomething for Uuid {
    fn do_it(&self) {
        println!("Done");
    }
}

A separate crate, my_application, uses prost to generate message types which reference Uuid:

// my_application.proto

syntax = "proto3";
package my_application;

import "uuid.proto";

message MyMessage {
    uuid.Uuid message_id = 1;
    string some_payload = 2;
}

Additionally, my_application depends on the trait impls provided by the uuid crate:

// `main.rs` of `my_application`

use uuid::{DoSomething, Uuid};

include!(concat!(env!("OUT_DIR"), "/my_application.rs"));

pub fn process_message(msg: MyMessage) {
    if let Some(uuid) = msg.message_id {
        uuid.do_it();
    }
}

Without configuring uuid as an external path in my_application’s build.rs, prost would compile a completely separate version of the Uuid type, and process_message would fail to compile. However, if my_application configures uuid as an extern path with a call to .extern_path(".uuid", "::uuid"), prost will use the external type instead of compiling a new version of Uuid. Note that the configuration could also be specified as .extern_path(".uuid.Uuid", "::uuid::Uuid") if only the Uuid type were externally provided, and not the whole uuid package.

Usage

extern_path takes a fully-qualified Protobuf path, and the corresponding Rust path that it will be substituted with in generated code. The Protobuf path can refer to a package or a type, and the Rust path should correspondingly refer to a Rust module or type.

// Declare the `uuid` Protobuf package and all nested packages and types as externally
// provided by the `uuid` crate.
config.extern_path(".uuid", "::uuid");

// Declare the `foo.bar.baz` Protobuf package and all nested packages and types as
// externally provided by the `foo_bar_baz` crate.
config.extern_path(".foo.bar.baz", "::foo_bar_baz");

// Declare the `uuid.Uuid` Protobuf type (and all nested types) as externally provided
// by the `uuid` crate's `Uuid` type.
config.extern_path(".uuid.Uuid", "::uuid::Uuid");

When set, the FileDescriptorSet generated by protoc is written to the provided filesystem path.

This option can be used in conjunction with the include_bytes! macro and the types in the prost-types crate for implementing reflection capabilities, among other things.

Example

In build.rs:

config.file_descriptor_set_path(
    PathBuf::from(env::var("OUT_DIR").expect("OUT_DIR environment variable not set"))
        .join("file_descriptor_set.bin"));

In lib.rs:

let file_descriptor_set_bytes = include_bytes!(concat!(env!("OUT_DIR"), "/file_descriptor_set.bin"));
let file_descriptor_set = prost_types::FileDescriptorSet::decode(&file_descriptor_set_bytes[..]).unwrap();

In combination with with file_descriptor_set_path, this can be used to provide a file descriptor set as an input file, rather than having prost-build generate the file by calling protoc.

In build.rs:

config.file_descriptor_set_path("path/from/build/system")
    .skip_protoc_run()
    .compile_protos(&["src/items.proto"], &["src/"]);

Configures the code generator to not strip the enum name from variant names.

Protobuf enum definitions commonly include the enum name as a prefix of every variant name. This style is non-idiomatic in Rust, so by default prost strips the enum name prefix from variants which include it. Configuring this option prevents prost from stripping the prefix.

Configures the output directory where generated Rust files will be written.

If unset, defaults to the OUT_DIR environment variable. OUT_DIR is set by Cargo when executing build scripts, so out_dir typically does not need to be configured.

Configures what filename protobufs with no package definition are written to.

Configures the path that’s used for deriving Message for generated messages. This is mainly useful for generating crates that wish to re-export prost. Defaults to ::prost::Message if not specified.

Add an argument to the protoc protobuf compilation invocation.

Example build.rs
fn main() -> Result<()> {
  let mut prost_build = prost_build::Config::new();
  // Enable a protoc experimental feature.
  prost_build.protoc_arg("--experimental_allow_proto3_optional");
  prost_build.compile_protos(&["src/frontend.proto", "src/backend.proto"], &["src"])?;
  Ok(())
}

Configures the optional module filename for easy inclusion of all generated Rust files

If set, generates a file (inside the OUT_DIR or out_dir() as appropriate) which contains a set of pub mod XXX statements combining to load all Rust files generated. This can allow for a shortcut where multiple related proto files have been compiled together resulting in a semi-complex set of includes.

Turning a need for:

pub mod Foo {
    pub mod Bar {
        include!(concat!(env!("OUT_DIR"), "/foo.bar.rs"));
    }
    pub mod Baz {
        include!(concat!(env!("OUT_DIR"), "/foo.baz.rs"));
    }
}

Into the simpler:

include!(concat!(env!("OUT_DIR"), "/_includes.rs"));

Configures the code generator to format the output code via prettyplease.

By default, this is enabled but if the format feature is not enabled this does nothing.

Compile .proto files into Rust files during a Cargo build with additional code generator configuration options.

This method is like the prost_build::compile_protos function, with the added ability to specify non-default code generation options. See that function for more information about the arguments and generated outputs.

The protos and includes arguments are ignored if skip_protoc_run is specified.

Example build.rs
fn main() -> Result<()> {
  let mut prost_build = prost_build::Config::new();
  prost_build.btree_map(&["."]);
  prost_build.compile_protos(&["src/frontend.proto", "src/backend.proto"], &["src"])?;
  Ok(())
}
Examples found in repository?
src/lib.rs (line 1267)
1266
1267
1268
pub fn compile_protos(protos: &[impl AsRef<Path>], includes: &[impl AsRef<Path>]) -> Result<()> {
    Config::new().compile_protos(protos, includes)
}

Processes a set of modules and file descriptors, returning a map of modules to generated code contents.

This is generally used when control over the output should not be managed by Prost, such as in a flow for a protoc code generating plugin. When compiling as part of a build.rs file, instead use compile_protos().

Examples found in repository?
src/lib.rs (line 935)
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
    pub fn compile_protos(
        &mut self,
        protos: &[impl AsRef<Path>],
        includes: &[impl AsRef<Path>],
    ) -> Result<()> {
        let mut target_is_env = false;
        let target: PathBuf = self.out_dir.clone().map(Ok).unwrap_or_else(|| {
            env::var_os("OUT_DIR")
                .ok_or_else(|| {
                    Error::new(ErrorKind::Other, "OUT_DIR environment variable is not set")
                })
                .map(|val| {
                    target_is_env = true;
                    Into::into(val)
                })
        })?;

        // TODO: This should probably emit 'rerun-if-changed=PATH' directives for cargo, however
        // according to [1] if any are output then those paths replace the default crate root,
        // which is undesirable. Figure out how to do it in an additive way; perhaps gcc-rs has
        // this figured out.
        // [1]: http://doc.crates.io/build-script.html#outputs-of-the-build-script

        let tmp;
        let file_descriptor_set_path = if let Some(path) = &self.file_descriptor_set_path {
            path.clone()
        } else {
            if self.skip_protoc_run {
                return Err(Error::new(
                    ErrorKind::Other,
                    "file_descriptor_set_path is required with skip_protoc_run",
                ));
            }
            tmp = tempfile::Builder::new().prefix("prost-build").tempdir()?;
            tmp.path().join("prost-descriptor-set")
        };

        if !self.skip_protoc_run {
            let protoc = protoc_from_env();

            let mut cmd = Command::new(protoc.clone());
            cmd.arg("--include_imports")
                .arg("--include_source_info")
                .arg("-o")
                .arg(&file_descriptor_set_path);

            for include in includes {
                if include.as_ref().exists() {
                    cmd.arg("-I").arg(include.as_ref());
                } else {
                    debug!(
                        "ignoring {} since it does not exist.",
                        include.as_ref().display()
                    )
                }
            }

            // Set the protoc include after the user includes in case the user wants to
            // override one of the built-in .protos.
            if let Some(protoc_include) = protoc_include_from_env() {
                cmd.arg("-I").arg(protoc_include);
            }

            for arg in &self.protoc_args {
                cmd.arg(arg);
            }

            for proto in protos {
                cmd.arg(proto.as_ref());
            }

            debug!("Running: {:?}", cmd);

            let output = cmd.output().map_err(|error| {
                Error::new(
                    error.kind(),
                    format!("failed to invoke protoc (hint: https://docs.rs/prost-build/#sourcing-protoc): (path: {:?}): {}", &protoc, error),
                )
            })?;

            if !output.status.success() {
                return Err(Error::new(
                    ErrorKind::Other,
                    format!("protoc failed: {}", String::from_utf8_lossy(&output.stderr)),
                ));
            }
        }

        let buf = fs::read(&file_descriptor_set_path).map_err(|e| {
            Error::new(
                e.kind(),
                format!(
                    "unable to open file_descriptor_set_path: {:?}, OS: {}",
                    &file_descriptor_set_path, e
                ),
            )
        })?;
        let file_descriptor_set = FileDescriptorSet::decode(&*buf).map_err(|error| {
            Error::new(
                ErrorKind::InvalidInput,
                format!("invalid FileDescriptorSet: {}", error),
            )
        })?;

        let requests = file_descriptor_set
            .file
            .into_iter()
            .map(|descriptor| {
                (
                    Module::from_protobuf_package_name(descriptor.package()),
                    descriptor,
                )
            })
            .collect::<Vec<_>>();

        let file_names = requests
            .iter()
            .map(|req| {
                (
                    req.0.clone(),
                    req.0.to_file_name_or(&self.default_package_filename),
                )
            })
            .collect::<HashMap<Module, String>>();

        let modules = self.generate(requests)?;
        for (module, content) in &modules {
            let file_name = file_names
                .get(module)
                .expect("every module should have a filename");
            let output_path = target.join(file_name);

            let previous_content = fs::read(&output_path);

            if previous_content
                .map(|previous_content| previous_content == content.as_bytes())
                .unwrap_or(false)
            {
                trace!("unchanged: {:?}", file_name);
            } else {
                trace!("writing: {:?}", file_name);
                fs::write(output_path, content)?;
            }
        }

        if let Some(ref include_file) = self.include_file {
            trace!("Writing include file: {:?}", target.join(include_file));
            let mut file = fs::File::create(target.join(include_file))?;
            self.write_includes(
                modules.keys().collect(),
                &mut file,
                0,
                if target_is_env { None } else { Some(&target) },
            )?;
            file.flush()?;
        }

        Ok(())
    }

Trait Implementations§

Formats the value using the given formatter. Read more
Returns the “default value” for a type. Read more

Auto Trait Implementations§

Blanket Implementations§

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more

Returns the argument unchanged.

Calls U::from(self).

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

The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.