### compile_protos method documentation with example Source: https://docs.rs/prost-build/latest/src/prost_build/config.rs.html Documentation for the `compile_protos` method, including an example `build.rs` that uses `prost_build::Config::new()`, `btree_map`, and `compile_protos`. The example is marked as `no_run` and shows how to compile proto files with additional configuration. ```rust /// 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` /// /// ```rust,no_run /// # use std::io::Result; /// 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(()) /// } /// ``` ``` -------------------------------- ### load_fds example build.rs Source: https://docs.rs/prost-build/latest/prost_build/struct.Config.html?search=u32+-%3E+bool Example `build.rs` for `Config::load_fds`. It loads `.proto` files into a `FileDescriptorSet`, then iterates over services and methods to add custom `#[derive(...)]` attributes to input and output message types before compilation. ```rust fn main() -> std::io::Result<()> { let mut config = Config::new(); let file_descriptor_set = config.load_fds(&["src/frontend.proto", "src/backend.proto"], &["src"])?; // Add custom attributes to messages that are service inputs or outputs. for file in &file_descriptor_set.file { for service in &file.service { for method in &service.method { if let Some(input) = &method.input_type { config.message_attribute(input, "#[derive(custom_proto::Input)]"); } if let Some(output) = &method.output_type { config.message_attribute(output, "#[derive(custom_proto::Output)]"); } } } } } ``` -------------------------------- ### Config struct and btree_map example Source: https://docs.rs/prost-build/latest/src/prost_build/config.rs.html?search=std%3A%3Avec The source shows the beginning of the `Config` struct definition and its `btree_map` method documentation, including a Rust code example that demonstrates various path patterns for `config.btree_map`. The example is truncated at the end of the method body, but the visible code is extracted verbatim. ```rust use std::collections::HashMap; use std::default; use std::env; use std::ffi::{OsStr, OsString}; use std::fmt; use std::fs; use std::io::{Error, ErrorKind, Result, Write}; use std::path::{Path, PathBuf}; use std::process::Command; use log::debug; use log::trace; use prost::Message; use prost_types::{FileDescriptorProto, FileDescriptorSet}; use crate::code_generator::CodeGenerator; use crate::context::Context; use crate::extern_paths::ExternPaths; use crate::message_graph::MessageGraph; use crate::path::PathMap; use crate::BytesType; use crate::MapType; use crate::Module; use crate::ServiceGenerator; /// Configuration options for Protobuf code generation. /// /// This configuration builder can be used to set non-default code generation options. pub struct Config { pub(crate) file_descriptor_set_path: Option, pub(crate) service_generator: Option>, pub(crate) map_type: PathMap, pub(crate) bytes_type: PathMap, pub(crate) type_attributes: PathMap, pub(crate) message_attributes: PathMap, pub(crate) enum_attributes: PathMap, pub(crate) field_attributes: PathMap, pub(crate) boxed: PathMap<()>, pub(crate) prost_types: bool, pub(crate) strip_enum_prefix: bool, pub(crate) out_dir: Option, pub(crate) extern_paths: Vec<(String, String)>, pub(crate) default_package_filename: String, pub(crate) enable_type_names: bool, pub(crate) type_name_domains: PathMap, pub(crate) protoc_args: Vec, pub(crate) protoc_executable: PathBuf, pub(crate) disable_comments: PathMap<()>, pub(crate) skip_debug: PathMap<()>, pub(crate) skip_protoc_run: bool, pub(crate) skip_source_info: bool, pub(crate) include_file: Option, pub(crate) prost_path: Option, pub(crate) prost_types_path: Option, #[cfg(feature = "format")] pub(crate) fmt: bool, } impl Config { /// Creates a new code generator configuration with default options. pub fn new() -> Config { Config::default() } /// Configure the code generator to generate Rust [`BTreeMap`][1] fields for Protobuf /// [`map`][2] 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`][3]. /// /// The matching is done on the Protobuf names, before converting to Rust-friendly casing /// standards. /// /// # Examples /// /// ```rust /// # let mut config = prost_build::Config::new(); /// // 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"]); /// ``` /// /// [1]: https://doc.rust-lang.org/std/collections/struct.BTreeMap.html /// [2]: https://protobuf.dev/programming-guides/proto3/#maps /// [3]: https://doc.rust-lang.org/std/collections/struct.HashMap.html pub fn btree_map(&mut self, paths: I) -> &mut Self where I: IntoIterator, S: AsRef, { self.map_type.clear(); for matcher in paths { self.map_type } } } ``` -------------------------------- ### Compile protos with Config::compile_protos in build.rs Source: https://docs.rs/prost-build/latest/src/prost_build/config.rs.html?search=std%3A%3Avec Example `build.rs` for `Config::compile_protos` with `btree_map` and custom includes. The `protos` and `includes` arguments are ignored if `skip_protoc_run` is set. ```rust use std::io::Result; 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(()) } ``` -------------------------------- ### assert_starts_with macro Source: https://docs.rs/prost-build/latest/src/prost_build/config.rs.html?search=Option%3CT%3E%2C+%28T+-%3E+U%29+-%3E+Option%3CU%3E Defines a macro that asserts a string starts with a given prefix, panicking with a formatted message on failure. ```rust macro_rules! assert_starts_with { ($left:expr, $right:expr) => { match (&$left, &$right) { (left_val, right_val) => { if !(left_val.starts_with(right_val)) { panic!( "assertion 'starts_with` failed:\nleft: {}\nright: {}", left_val, right_val ) } } } }; } ``` -------------------------------- ### Create a new Rust library crate Source: https://docs.rs/prost-build/latest/src/prost_build/lib.rs.html?search=u32+-%3E+bool Creates a new Rust library crate named 'snazzy' and changes into its directory. This is the first step in the example project. ```bash $ cargo new --lib snazzy && cd snazzy ``` -------------------------------- ### Configure prost_build skip_protoc_run and skip_source_info Source: https://docs.rs/prost-build/latest/src/prost_build/config.rs.html?search= Configure prost_build to skip running protoc or to skip source info. Both examples show chaining file_descriptor_set_path with the respective option and compile_protos. The first skips protoc execution; the second omits --include_source_info to reduce FileDescriptorSet size. ```rust config.file_descriptor_set_path("path/from/build/system") .skip_protoc_run() .compile_protos(&["src/items.proto"], &["src/"]); ``` ```rust config.file_descriptor_set_path("path/from/build/system") .skip_source_info() .compile_protos(&["src/items.proto"], &["src/"]); ``` -------------------------------- ### Compile protoc from source with protobuf-src Source: https://docs.rs/prost-build/latest/src/prost_build/lib.rs.html?search=u32+-%3E+bool Configures prost-build to use a protoc executable compiled from source via the protobuf-src crate. This is an alternative to installing protoc separately. ```rust let mut prost_build = prost_build::Config::new(); prost_build.protoc_executable(protobuf_src::protoc()); // Now compile your proto files with the configuration ``` -------------------------------- ### Config::btree_map() method with examples Source: https://docs.rs/prost-build/latest/src/prost_build/config.rs.html?search=Option%3CT%3E%2C+%28T+-%3E+U%29+-%3E+Option%3CU%3E Configures the code generator to generate Rust `BTreeMap` fields for Protobuf map fields. The method takes paths to specific fields, messages, or packages. Paths with a leading `.` are fully qualified; others are suffix matched. The examples show various path patterns. ```rust /// Configure the code generator to generate Rust [`BTreeMap`][1] fields for Protobuf /// [`map`][2] 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`][3]. /// /// The matching is done on the Protobuf names, before converting to Rust-friendly casing /// standards. /// /// # Examples /// /// ```rust /// # let mut config = prost_build::Config::new(); /// // 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"]); /// ``` /// /// [1]: https://doc.rust-lang.org/std/collections/struct.BTreeMap.html /// [2]: https://protobuf.dev/programming-guides/proto3/#maps /// [3]: https://doc.rust-lang.org/std/collections/struct.HashMap.html pub fn btree_map(&mut self, paths: I) -> &mut Self where I: IntoIterator, S: AsRef, { self.map_type.clear(); for matcher in paths { self.map_type ``` -------------------------------- ### extern_path example: uuid crate, proto, and main.rs Source: https://docs.rs/prost-build/latest/src/prost_build/config.rs.html?search=Option%3CT%3E%2C+%28T+-%3E+U%29+-%3E+Option%3CU%3E Shows the three files needed to use `extern_path` with a custom type: the `uuid` crate's `lib.rs` defining the trait and impl, the `my_application.proto` file importing `uuid.proto` and using `uuid.Uuid`, and `my_application`'s `main.rs` that includes generated code and calls `do_it`. Without configuring `uuid` as an extern path, `prost` would compile a separate `Uuid` type and `process_message` would fail to compile. ```rust /// // 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"); /// } /// } /// ``` ``` ```proto // my_application.proto syntax = "proto3"; package my_application; import "uuid.proto"; message MyMessage { uuid.Uuid message_id = 1; string some_payload = 2; } ``` ```rust // `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(); } } ``` -------------------------------- ### Rust no_run example: compile_fds with FileDescriptorSet Source: https://docs.rs/prost-build/latest/src/prost_build/lib.rs.html?search=std%3A%3Avec Shows a build.rs main function calling prost_build::compile_fds with a FileDescriptorSet obtained from a helper function. Can be combined with the protox crate. Uses an #[allow(dead_code)]-style todo!() stub; run with cargo build. ```rust ```rust,no_run # use prost_types::FileDescriptorSet; # fn fds() -> FileDescriptorSet { todo!() } fn main() -> std::io::Result<()> { let file_descriptor_set = fds(); prost_build::compile_fds(file_descriptor_set) } ``` ``` -------------------------------- ### Load and inspect FileDescriptorSet with Config::load_fds in build.rs Source: https://docs.rs/prost-build/latest/src/prost_build/config.rs.html Use in a build.rs to load a FileDescriptorSet with Config::load_fds, inspect the descriptors, and add custom attributes to service input/output messages before compiling with Config::compile_fds. The example shows how to iterate over the descriptor set and apply message_attribute for each input and output type. ```rust use prost_types::FileDescriptorSet; use prost_build::Config; fn main() -> std::io::Result<()> { let mut config = Config::new(); let file_descriptor_set = config.load_fds(&["src/frontend.proto", "src/backend.proto"], &["src"])?; // Add custom attributes to messages that are service inputs or outputs. for file in &file_descriptor_set.file { for service in &file.service { for method in &service.method { if let Some(input) = &method.input_type { config.message_attribute(input, "#[derive(custom_proto::Input)]"); } if let Some(output) = &method.output_type { config.message_attribute(output, "#[derive(custom_proto::Output)]"); } } } } config.compile_fds(file_descriptor_set) } ``` -------------------------------- ### Start of append_map_field with key type resolution Source: https://docs.rs/prost-build/latest/src/prost_build/code_generator.rs.html?search=std%3A%3Avec Starts the implementation of append_map_field, which resolves the key type for a map field. The snippet is incomplete as shown in the source; it only includes the function signature and the first line of the body. ```rust fn append_map_field( &mut self, fq_message_name: &str, field: &Field, key: &FieldDescriptorProto, value: &FieldDescriptorProto, ) { let key_ty = self.resolve_type(key, fq_message_name); ``` -------------------------------- ### PathMap and path matching utilities for Protobuf paths Source: https://docs.rs/prost-build/latest/src/prost_build/path.rs.html?search=Option%3CT%3E%2C+%28T+-%3E+U%29+-%3E+Option%3CU%3E Defines the PathMap type and its iterator for matching fully-qualified Protobuf paths. The map stores matchers as (String, T) pairs and provides insert, get, get_field, get_first, get_first_field, and clear methods. Matching tries the full path, then suffixes, then prefixes, then the global path ".". The Iter iterator yields values whose stored path matches any sub-path of the given path. The sub_path_iter, prefixes, and suffixes helper functions generate the candidate paths in decreasing length order. The module includes unit tests verifying the generated path sequences. ```rust 1//! Utilities for working with Protobuf paths. 2 3use std::iter; 4 5/// Maps a fully-qualified Protobuf path to a value using path matchers. 6#[derive(Clone, Debug, Default)] 7pub(crate) struct PathMap { 8 // insertion order might actually matter (to avoid warning about legacy-derive-helpers) 9 // see: https://doc.rust-lang.org/rustc/lints/listing/warn-by-default.html#legacy-derive-helpers 10 pub(crate) matchers: Vec<(String, T)>, 11} 12 13impl PathMap { 14 /// Inserts a new matcher and associated value to the path map. 15 pub(crate) fn insert(&mut self, matcher: String, value: T) { 16 self.matchers.push((matcher, value)); 17 } 18 19 /// Returns a iterator over all the value matching the given fd_path and associated suffix/prefix path 20 pub(crate) fn get(&self, fq_path: &str) -> Iter<'_, T> { 21 Iter::new(self, fq_path.to_string()) 22 } 23 24 /// Returns a iterator over all the value matching the path `fq_path.field` and associated suffix/prefix path 25 pub(crate) fn get_field(&self, fq_path: &str, field: &str) -> Iter<'_, T> { 26 Iter::new(self, format!("{fq_path}.{field}")) 27 } 28 29 /// Returns the first value found matching the given path 30 /// If nothing matches the path, suffix paths will be tried, then prefix paths, then the global path 31 pub(crate) fn get_first<'a>(&'a self, fq_path: &'_ str) -> Option<&'a T> { 32 self.find_best_matching(fq_path) 33 } 34 35 /// Returns the first value found matching the path `fq_path.field` 36 /// If nothing matches the path, suffix paths will be tried, then prefix paths, then the global path 37 pub(crate) fn get_first_field<'a>(&'a self, fq_path: &'_ str, field: &'_ str) -> Option<&'a T> { 38 self.find_best_matching(&format!("{fq_path}.{field}")) 39 } 40 41 /// Removes all matchers from the path map. 42 pub(crate) fn clear(&mut self) { 43 self.matchers.clear(); 44 } 45 46 /// Returns the first value found best matching the path 47 /// See [sub_path_iter()] for paths test order 48 fn find_best_matching(&self, full_path: &str) -> Option<&T> { 49 sub_path_iter(full_path).find_map(|path| { 50 self.matchers 51 .iter() 52 .find(|(p, _)| p == path) 53 .map(|(_, v)| v) 54 }) 55 } 56} 57 58/// Iterator inside a PathMap that only returns values that matches a given path 59pub(crate) struct Iter<'a, T> { 60 iter: std::slice::Iter<'a, (String, T)>, 61 path: String, 62} 63 64impl<'a, T> Iter<'a, T> { 65 fn new(map: &'a PathMap, path: String) -> Self { 66 Self { 67 iter: map.matchers.iter(), 68 path, 69 } 70 } 71 72 fn is_match(&self, path: &str) -> bool { 73 sub_path_iter(self.path.as_str()).any(|p| p == path) 74 } 75} 76 77impl<'a, T> std::iter::Iterator for Iter<'a, T> { 78 type Item = &'a T; 79 80 fn next(&mut self) -> Option { 81 loop { 82 match self.iter.next() { 83 Some((p, v)) => { 84 if self.is_match(p) { 85 return Some(v); 86 } 87 } 88 None => return None, 89 } 90 } 91 } 92} 93 94impl std::iter::FusedIterator for Iter<'_, T> {} 95 96/// Given a fully-qualified path, returns a sequence of paths: 97/// - the path itself 98/// - the sequence of suffix paths 99/// - the sequence of prefix paths 100/// - the global path 101/// 102/// Example: sub_path_iter(".a.b.c") -> [".a.b.c", "a.b.c", "b.c", "c", ".a.b", ".a", "."] 103fn sub_path_iter(full_path: &str) -> impl Iterator { 104 // First, try matching the path. 105 iter::once(full_path) 106 // Then, try matching path suffixes. 107 .chain(suffixes(full_path)) 108 // Then, try matching path prefixes. 109 .chain(prefixes(full_path)) 110 // Then, match the global path. 111 .chain(iter::once(".")) 112} 113 114/// Given a fully-qualified path, returns a sequence of fully-qualified paths which match a prefix 115/// of the input path, in decreasing path-length order. 116/// 117/// Example: prefixes(".a.b.c.d") -> [".a.b.c", ".a.b", ".a"] 118fn prefixes(fq_path: &str) -> impl Iterator { 119 std::iter::successors(Some(fq_path), |path| { 120 path.rsplit_once('.') 121 .map(|x| x.0) 122 .filter(|path| !path.is_empty()) 123 }) 124 .skip(1) 125} 126 127/// Given a fully-qualified path, returns a sequence of paths which match the suffix of the input 128/// path, in decreasing path-length order. 129/// 130/// Example: suffixes(".a.b.c.d") -> ["a.b.c.d", "b.c.d", "c.d", "d"] 131fn suffixes(fq_path: &str) -> impl Iterator { 132 std::iter::successors(Some(fq_path), |path| { 133 path.rsplit_once('.') 134 .map(|x| x.1) 135 .filter(|path| !path.is_empty()) 136 }) 137 .skip(1) 138} 139 140#[cfg(test)] 141mod tests { 142 use super::*; 143 144 #[test] 145 fn test_sub_path_iter() { 146 let paths: Vec<_> = sub_path_iter(".a.b.c").collect(); 147 assert_eq!(paths, vec![".a.b.c", "a.b.c", "b.c", "c", ".a.b", ".a", "."]); 148 } 149 150 #[test] fn test_prefixes() { 151 let paths: Vec<_> = prefixes(".a.b.c.d").collect(); 152 assert_eq!(paths, vec![".a.b.c", ".a.b", ".a"]); 153 } 154 #[test] fn test_suffixes() { let paths: Vec<_> = suffixes(".a.b.c.d").collect(); assert_eq!(paths, vec!["a.b.c.d", "b.c.d", "c.d", "d"]); } } ``` -------------------------------- ### prost_build::ident.rs identifier utilities (sanitize_identifier, to_snake, to_upper_camel, strip_enum_prefix) Source: https://docs.rs/prost-build/latest/src/prost_build/ident.rs.html?search=Option%3CT%3E%2C+%28T+-%3E+U%29+-%3E+Option%3CU%3E Provides the core identifier utilities for prost-build: sanitize_identifier, to_snake, to_upper_camel, and strip_enum_prefix. sanitize_identifier prefixes Rust keywords with r# (except unsupported ones like self, which get an underscore suffix) and prefixes identifiers starting with a digit with an underscore. The included tests verify the expected raw-identifier output for each keyword. ```rust 1//! Utility functions for working with identifiers. 2 3use heck::{ToSnakeCase, ToUpperCamelCase}; 4 5pub fn sanitize_identifier(s: impl AsRef) -> String { 6 let ident = s.as_ref(); 7 // Use a raw identifier if the identifier matches a Rust keyword: 8 // https://doc.rust-lang.org/reference/keywords.html. 9 match ident { 10 // 2015 strict keywords. 11 | "as" | "break" | "const" | "continue" | "else" | "enum" | "false" 12 | "fn" | "for" | "if" | "impl" | "in" | "let" | "loop" | "match" | "mod" | "move" | "mut" 13 | "pub" | "ref" | "return" | "static" | "struct" | "trait" | "true" 14 | "type" | "unsafe" | "use" | "where" | "while" 15 // 2018 strict keywords. 16 | "dyn" 17 // 2015 reserved keywords. 18 | "abstract" | "become" | "box" | "do" | "final" | "macro" | "override" | "priv" | "typeof" 19 | "unsized" | "virtual" | "yield" 20 // 2018 reserved keywords. 21 | "async" | "await" | "try" 22 // 2024 reserved keywords. 23 | "gen" => format!("r#{ident}"), 24 // the following keywords are not supported as raw identifiers and are therefore suffixed with an underscore. 25 "_" | "super" | "self" | "Self" | "extern" | "crate" => format!("{ident}_"), 26 // the following keywords begin with a number and are therefore prefixed with an underscore. 27 s if s.starts_with(|c: char| c.is_numeric()) => format!("_{ident}"), 28 _ => ident.to_string(), 29 } 30} 31 32/// Converts a `camelCase` or `SCREAMING_SNAKE_CASE` identifier to a `lower_snake` case Rust field 33/// identifier. 34pub fn to_snake(s: impl AsRef) -> String { 35 sanitize_identifier(s.as_ref().to_snake_case()) 36} 37 38/// Converts a `snake_case` identifier to an `UpperCamel` case Rust type identifier. 39pub fn to_upper_camel(s: impl AsRef) -> String { 40 sanitize_identifier(s.as_ref().to_upper_camel_case()) 41} 42 43/// Strip an enum's type name from the prefix of an enum value. 44/// 45/// This function assumes that both have been formatted to Rust's 46/// upper camel case naming conventions. 47/// 48/// It also tries to handle cases where the stripped name would be 49/// invalid - for example, if it were to begin with a number. 50/// /// If the stripped name is `"Self"`, it will be replaced with `"Self_"` 51pub fn strip_enum_prefix(prefix: &str, name: &str) -> String { 52 let stripped = name.strip_prefix(prefix).unwrap_or(name); 53 54 // If the next character after the stripped prefix is not 55 // uppercase, then it means that we didn't have a true prefix - 56 // for example, "Foo" should not be stripped from "Foobar". 57 let stripped = if stripped 58 .chars() 59 .next() 60 .map(char::is_uppercase) 61 .unwrap_or(false) 62 { 63 stripped 64 } else { 65 name 66 }; 67 sanitize_identifier(stripped) 68} 69 70#[cfg(test)] 71mod tests { 72 use super::*; 73 74 #[test] 75 fn test_sanitize_identifier() { 76 assert_eq!(sanitize_identifier("as"), "r#as"); 77 assert_eq!(sanitize_identifier("break"), "r#break"); 78 assert_eq!(sanitize_identifier("const"), "r#const"); 79 assert_eq!(sanitize_identifier("continue"), "r#continue"); 80 assert_eq!(sanitize_identifier("else"), "r#else"); 81 assert_eq!(sanitize_identifier("enum"), "r#enum"); 82 assert_eq!(sanitize_identifier("false"), "r#false"); 83 assert_eq!(sanitize_identifier("fn"), "r#fn"); 84 assert_eq!(sanitize_identifier("for"), "r#for"); 85 assert_eq!(sanitize_identifier("if"), "r#if"); 86 assert_eq!(sanitize_identifier("impl"), "r#impl"); 87 assert_eq!(sanitize_identifier("in"), "r#in"); 88 assert_eq!(sanitize_identifier("let"), "r#let"); 89 assert_eq!(sanitize_identifier("loop"), "r#loop"); 90 assert_eq!(sanitize_identifier("match"), "r#match"); 91 assert_eq!(sanitize_identifier("mod"), "r#mod"); 92 assert_eq!(sanitize_identifier("move"), "r#move"); 93 assert_eq!(sanitize_identifier("mut"), "r#mut"); 94 assert_eq!(sanitize_identifier("pub"), "r#pub"); 95 assert_eq!(sanitize_identifier("ref"), "r#ref"); 96 assert_eq!(sanitize_identifier("return"), "r#return"); 97 assert_eq!(sanitize_identifier("static"), "r#static"); 98 assert_eq!(sanitize_identifier("struct"), "r#struct"); 99 assert_eq!(sanitize_identifier("trait"), "r#trait"); 100 assert_eq!(sanitize_identifier("true"), "r#true"); 101 assert_eq!(sanitize_identifier("type"), "r#type"); 102 assert_eq!(sanitize_identifier("unsafe"), "r#unsafe"); 103 assert_eq!(sanitize_identifier("use"), "r#use"); 104 assert_eq!(sanitize_identifier("where"), "r#where"); ``` -------------------------------- ### Set up a new crate with prost-build and prost dependencies Source: https://docs.rs/prost-build/latest/prost_build/index.html?search=u32+-%3E+bool Creates a new library crate named `snazzy` and adds `prost-build` and `prost` as dependencies. Run these commands in a terminal. ```shell $ cargo new --lib snazzy && cd snazzy ``` ```shell $ cargo add --build prost-build $ cargo add prost ``` -------------------------------- ### protoc_from_env Source: https://docs.rs/prost-build/latest/prost_build/fn.protoc_from_env.html Returns the path to the `protoc` binary. ```APIDOC ## protoc_from_env ### Description Returns the path to the `protoc` binary. ### Method N/A ### Endpoint N/A ### Parameters None ### Request Example N/A ### Response #### Success Response (200) - **path** (PathBuf) - The path to the `protoc` binary. #### Response Example N/A ``` -------------------------------- ### field_attribute example Source: https://docs.rs/prost-build/latest/prost_build/struct.Config.html Shows how to add a serde rename attribute to fields named 'in' using field_attribute. ```rust config.field_attribute("in", "#[serde(rename = \"in\")]"); ``` -------------------------------- ### Config::new() method Source: https://docs.rs/prost-build/latest/src/prost_build/config.rs.html?search=Option%3CT%3E%2C+%28T+-%3E+U%29+-%3E+Option%3CU%3E Creates a new `Config` instance with default options by calling `Config::default()`. ```rust impl Config { /// Creates a new code generator configuration with default options. pub fn new() -> Config { Config::default() } ``` -------------------------------- ### should_skip_debug method Source: https://docs.rs/prost-build/latest/src/prost_build/context.rs.html?search=std%3A%3Avec Returns whether the named message should skip generating the Debug implementation. Asserts that the message name starts with a dot. ```rust pub fn should_skip_debug(&self, fq_message_name: &str) -> bool { assert_eq!(b'.', fq_message_name.as_bytes()[0]); self.config.skip_debug.get(fq_message_name).next().is_some() } ``` -------------------------------- ### protoc_from_env Source: https://docs.rs/prost-build/latest/prost_build/fn.protoc_from_env.html?search=Option%3CT%3E%2C+%28T+-%3E+U%29+-%3E+Option%3CU%3E Returns the path to the `protoc` binary. This function is part of the prost-build crate and can be called directly by users to locate the protoc compiler. ```APIDOC ## protoc_from_env ### Description Returns the path to the `protoc` binary. ### Function Signature ```rust pub fn protoc_from_env() -> PathBuf ``` ### Returns - **PathBuf** - The path to the `protoc` binary. ``` -------------------------------- ### test_error_protoc_not_executable test Source: https://docs.rs/prost-build/latest/src/prost_build/config.rs.html?search=Option%3CT%3E%2C+%28T+-%3E+U%29+-%3E+Option%3CU%3E Tests that `load_fds` returns an error when the configured `protoc` executable is not executable, checking the error message starts with the expected prefix. ```rust #[test] fn test_error_protoc_not_executable() { let mut config = Config::new(); config.protoc_executable("src/lib.rs"); let err = config.load_fds(&[""], &[""]).unwrap_err(); assert_starts_with!(err.to_string(), "failed to invoke protoc (hint: https://docs.rs/prost-build/#sourcing-protoc): (path: src/lib.rs): ") } ``` -------------------------------- ### sanitize_identifier Source: https://docs.rs/prost-build/latest/src/prost_build/ident.rs.html?search=Option%3CT%3E%2C+%28T+-%3E+U%29+-%3E+Option%3CU%3E Sanitizes an identifier by converting it to a raw identifier (r#) if it matches a Rust keyword, appending an underscore for unsupported keywords, or prefixing with an underscore if it starts with a digit. ```APIDOC ## sanitize_identifier ### Description Sanitizes an identifier by converting it to a raw identifier (r#) if it matches a Rust keyword, appending an underscore for unsupported keywords, or prefixing with an underscore if it starts with a digit. ### Function Signature pub fn sanitize_identifier(s: impl AsRef) -> String ### Parameters - **s** (impl AsRef) - Required - The identifier to sanitize. ### Returns - **String** - The sanitized identifier. ### Behavior - If the identifier matches a Rust keyword (e.g., "as", "break", "const"), it is prefixed with "r#" (e.g., "r#as"). - If the identifier is one of "_", "super", "self", "Self", "extern", "crate", an underscore is appended (e.g., "self_"). - If the identifier starts with a digit, an underscore is prepended (e.g., "_123"). - Otherwise, the identifier is returned unchanged. ``` -------------------------------- ### protoc_include_from_env() Source: https://docs.rs/prost-build/latest/prost_build/fn.protoc_include_from_env.html Returns the path to the Protobuf include directory. This function is part of the prost_build crate and is used to locate the directory containing Protobuf standard includes. ```APIDOC ## Function protoc_include_from_env ### Description Returns the path to the Protobuf include directory. ### Signature pub fn protoc_include_from_env() -> Option ### Parameters None ### Return Value - **Option** - The path to the Protobuf include directory, or None if not available. ### Example ```rust let include_dir = prost_build::protoc_include_from_env(); ``` ``` -------------------------------- ### protoc_from_env() Source: https://docs.rs/prost-build/latest/prost_build/fn.protoc_from_env.html?search=std%3A%3Avec Returns the path to the `protoc` binary. This function is part of the `prost_build` crate's public API and is used to locate the Protocol Buffers compiler. ```APIDOC ## protoc_from_env() ### Description Returns the path to the `protoc` binary. ### Function Signature ```rust pub fn protoc_from_env() -> PathBuf ``` ### Returns - `PathBuf` - The path to the `protoc` binary. ``` -------------------------------- ### Module::to_file_name_or Source: https://docs.rs/prost-build/latest/prost_build/struct.Module.html?search=u32+-%3E+bool Formats the module path into a filename for generated Rust code, using a default for the root if empty. ```APIDOC ## Module::to_file_name_or ### Description Formats the module path into a filename for generated Rust code. If the module path is empty, the provided default is used as the root of the filename. ### Method pub fn to_file_name_or(&self, default: &str) -> String ### Parameters - **default** (&str) - Required - The default root filename when the module path is empty. ### Returns - **String** - The formatted filename. ``` -------------------------------- ### Config::field_attribute() Source: https://docs.rs/prost-build/latest/prost_build/struct.Config.html?search=std%3A%3Avec Adds an additional attribute to matched fields. The `path` argument is a path matching any number of fields. These fields get the attribute. The `attribute` argument is 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. ```APIDOC ## Config::field_attribute() ### Description Add additional attribute to matched fields. The `path` argument is a path matching any number of fields. These fields get the attribute. For details about matching fields see `btree_map`. The `attribute` argument is 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. ### Method field_attribute ### Signature `pub fn field_attribute(&mut self, path: P, attribute: A) -> &mut Self where P: AsRef, A: AsRef` ### Parameters - **path** (AsRef) - Required - A path matching any number of fields. These fields get the attribute. For details about matching fields see `btree_map`. - **attribute** (AsRef) - Required - 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. ### Returns - **&mut Self** - The configuration builder for chaining. ### Examples ```rust // Prost renames fields named `in` to `in_`. But if serialized through serde, // they should as `in`. config.field_attribute("in", "#[serde(rename = \"in\")]"); ``` ``` -------------------------------- ### Module::to_file_name_or Source: https://docs.rs/prost-build/latest/prost_build/struct.Module.html?search= Formats the module path into a filename for generated Rust code, using a default for the root if empty. ```APIDOC ## Module::to_file_name_or ### Description Formats the module path into a filename for generated Rust code. If the module path is empty, the provided default is used to provide the root of the filename. ### Method pub fn to_file_name_or(&self, default: &str) -> String ### Parameters - **default** (&str) - Required - The default root to use if the module path is empty. ### Returns - **String** - The formatted filename. ``` -------------------------------- ### Set PROTOC environment variable Source: https://docs.rs/prost-build/latest/src/prost_build/lib.rs.html?search=u32+-%3E+bool Sets the PROTOC environment variable to the path of the protoc executable. This is used when protoc is installed in a non-standard location, such as via Homebrew on macOS. ```bash PROTOC=/usr/local/bin/protoc ``` -------------------------------- ### Get message name and fully qualified name Source: https://docs.rs/prost-build/latest/src/prost_build/code_generator.rs.html?search=Option%3CT%3E%2C+%28T+-%3E+U%29+-%3E+Option%3CU%3E Extracts the message name and computes its fully qualified name. This is a prerequisite for later operations that reference the message by its full path. ```rust let message_name = message.name().to_string(); let fq_message_name = self.fq_name(&message_name); ``` -------------------------------- ### pub fn protoc_executable(&mut self, executable: S) -> &mut Self where S: Into Source: https://docs.rs/prost-build/latest/prost_build/struct.Config.html?search= Set the path to the protoc executable to be used by prost-build. ```APIDOC ## pub fn protoc_executable(&mut self, executable: S) -> &mut Self where S: Into ### Description Set the path to `protoc` executable to be used by `prost-build`. Use the provided path to find `protoc`. This can either be a file name which is searched for in the `PATH` or an absolute path to use a specific executable. ### Parameters - **executable** (S where S: Into) - Required - The path or name of the protoc executable. ### Example `build.rs` ```rust fn main() -> Result<()> { let mut prost_build = prost_build::Config::new(); prost_build.protoc_executable("protoc-27.1"); prost_build.compile_protos(&["src/frontend.proto", "src/backend.proto"], &["src"])?; Ok(()) } ``` ``` -------------------------------- ### Compile FileDescriptorSet with prost_build::compile_fds in build.rs Source: https://docs.rs/prost-build/latest/src/prost_build/lib.rs.html?search= Call prost_build::compile_fds in a project's build.rs to generate code from a FileDescriptorSet. The example uses a placeholder fds() function that must be replaced with an actual FileDescriptorSet, such as one produced by protox. ```rust # use prost_types::FileDescriptorSet; # fn fds() -> FileDescriptorSet { todo!() } fn main() -> std::io::Result<()> { let file_descriptor_set = fds(); prost_build::compile_fds(file_descriptor_set) } ``` -------------------------------- ### Compile file descriptor set with prost_build::Config Source: https://docs.rs/prost-build/latest/prost_build/struct.Config.html?search=Option%3CT%3E%2C+%28T+-%3E+U%29+-%3E+Option%3CU%3E Compiles a file descriptor set into Rust code using a custom prost_build::Config. The example is incomplete as shown; it omits the closing brace and semicolon, and the file_descriptor_set variable is not defined in the snippet. ```rust fn main() -> Result<()> { let mut config = prost_build::Config::new(); config.compile_fds(file_descriptor_set) } ``` -------------------------------- ### protoc_include_from_env() Source: https://docs.rs/prost-build/latest/prost_build/fn.protoc_include_from_env.html?search= Returns the path to the Protobuf include directory. This function is part of the prost_build crate and can be called directly by users to obtain the include directory path for Protobuf compilation. ```APIDOC ## protoc_include_from_env() ### Description Returns the path to the Protobuf include directory. ### Function Signature ```rust pub fn protoc_include_from_env() -> Option ``` ### Parameters None ### Return Value - **Option** - The path to the Protobuf include directory, or `None` if not available. ### Usage Example ```rust use prost_build::protoc_include_from_env; if let Some(path) = protoc_include_from_env() { println!("Protobuf include directory: {:?}", path); } ``` ``` -------------------------------- ### pub fn default_package_filename(&mut self, filename: S) -> &mut Self where S: Into Source: https://docs.rs/prost-build/latest/prost_build/struct.Config.html?search= Configures what filename protobufs with no package definition are written to. The filename will be appended with the .rs extension. ```APIDOC ## pub fn default_package_filename(&mut self, filename: S) -> &mut Self where S: Into ### Description Configures what filename protobufs with no package definition are written to. The filename will be appended with the `.rs` extension. ### Parameters - **filename** (S where S: Into) - Required - The base filename (without .rs extension) for protobuf files that define no package. ``` -------------------------------- ### Implement ServiceGenerator to generate service trait Source: https://docs.rs/prost-build/latest/src/prost_build/lib.rs.html?search= Example ServiceGenerator implementation that generates a trait with methods for each service method. It appends service comments, method signatures, and a finalize method that adds a utils module. The finalize_package method is shown but references state that is not defined in this snippet. ```rust struct ServiceTraitGenerator; impl ServiceGenerator for ServiceTraitGenerator { fn generate(&mut self, service: Service, buf: &mut String) { // Generate a trait for the service. service.comments.append_with_indent(0, buf); buf.push_str(&format!("trait {} {{\n", &service.name)); // Generate the service methods. for method in service.methods { method.comments.append_with_indent(1, buf); buf.push_str(&format!( " fn {}(_: {}) -> {};\n", method.name, method.input_type, method.output_type )); } // Close out the trait. buf.push_str("}\n"); } fn finalize(&mut self, buf: &mut String) { // Needs to be present only once, no matter how many services there are buf.push_str("pub mod utils { }\n"); } fn finalize_package(&mut self, package: &str, _buf: &mut String) { let mut state = self.state.borrow_mut(); state.package_names.push(package.to_string()); } } ``` -------------------------------- ### Module::to_file_name_or Source: https://docs.rs/prost-build/latest/prost_build/struct.Module.html?search=std%3A%3Avec Formats the module path into a filename for generated Rust code. If the module path is empty, the provided default is used as the root of the filename. ```APIDOC ## Module::to_file_name_or ### Description Formats the module path into a filename for generated Rust code. If the module path is empty, `default` is used to provide the root of the filename. ### Method `pub fn to_file_name_or(&self, default: &str) -> String` ### Parameters - `default` (&str) - Required - The default root filename to use if the module path is empty. ### Returns A `String` representing the filename. ```