Trait prost_build::ServiceGenerator
source · pub trait ServiceGenerator {
fn generate(&mut self, service: Service, buf: &mut String);
fn finalize(&mut self, _buf: &mut String) { ... }
fn finalize_package(&mut self, _package: &str, _buf: &mut String) { ... }
}Expand description
A service generator takes a service descriptor and generates Rust code.
ServiceGenerator can be used to generate application-specific interfaces
or implementations for Protobuf service definitions.
Service generators are registered with a code generator using the
Config::service_generator method.
A viable scenario is that an RPC framework provides a service generator. It generates a trait describing methods of the service and some glue code to call the methods of the trait, defining details like how errors are handled or if it is asynchronous. Then the user provides an implementation of the generated trait in the application code and plugs it into the framework.
Such framework isn’t part of Prost at present.
Required Methods§
Provided Methods§
sourcefn finalize(&mut self, _buf: &mut String)
fn finalize(&mut self, _buf: &mut String)
Finalizes the generation process.
In case there’s something that needs to be output at the end of the generation process, it
goes here. Similar to generate, the output should be appended to
buf.
An example can be a module or other thing that needs to appear just once, not for each service generated.
This still can be called multiple times in a lifetime of the service generator, because it
is called once per .proto file.
The default implementation is empty and does nothing.
Examples found in repository?
47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117
pub fn generate(
config: &mut Config,
message_graph: &MessageGraph,
extern_paths: &ExternPaths,
file: FileDescriptorProto,
buf: &mut String,
) {
let source_info = file.source_code_info.map(|mut s| {
s.location.retain(|loc| {
let len = loc.path.len();
len > 0 && len % 2 == 0
});
s.location.sort_by(|a, b| a.path.cmp(&b.path));
s
});
let syntax = match file.syntax.as_ref().map(String::as_str) {
None | Some("proto2") => Syntax::Proto2,
Some("proto3") => Syntax::Proto3,
Some(s) => panic!("unknown syntax: {}", s),
};
let mut code_gen = CodeGenerator {
config,
package: file.package.unwrap_or_default(),
source_info,
syntax,
message_graph,
extern_paths,
depth: 0,
path: Vec::new(),
buf,
};
debug!(
"file: {:?}, package: {:?}",
file.name.as_ref().unwrap(),
code_gen.package
);
code_gen.path.push(4);
for (idx, message) in file.message_type.into_iter().enumerate() {
code_gen.path.push(idx as i32);
code_gen.append_message(message);
code_gen.path.pop();
}
code_gen.path.pop();
code_gen.path.push(5);
for (idx, desc) in file.enum_type.into_iter().enumerate() {
code_gen.path.push(idx as i32);
code_gen.append_enum(desc);
code_gen.path.pop();
}
code_gen.path.pop();
if code_gen.config.service_generator.is_some() {
code_gen.path.push(6);
for (idx, service) in file.service.into_iter().enumerate() {
code_gen.path.push(idx as i32);
code_gen.push_service(service);
code_gen.path.pop();
}
if let Some(service_generator) = code_gen.config.service_generator.as_mut() {
service_generator.finalize(code_gen.buf);
}
code_gen.path.pop();
}
}sourcefn finalize_package(&mut self, _package: &str, _buf: &mut String)
fn finalize_package(&mut self, _package: &str, _buf: &mut String)
Finalizes the generation process for an entire protobuf package.
This differs from finalize by where (and how often) it is called
during the service generator life cycle. This method is called once per protobuf package,
making it ideal for grouping services within a single package spread across multiple
.proto files.
The default implementation is empty and does nothing.
Examples found in repository?
1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079
pub fn generate(
&mut self,
requests: Vec<(Module, FileDescriptorProto)>,
) -> Result<HashMap<Module, String>> {
let mut modules = HashMap::new();
let mut packages = HashMap::new();
let message_graph = MessageGraph::new(requests.iter().map(|x| &x.1))
.map_err(|error| Error::new(ErrorKind::InvalidInput, error))?;
let extern_paths = ExternPaths::new(&self.extern_paths, self.prost_types)
.map_err(|error| Error::new(ErrorKind::InvalidInput, error))?;
for (request_module, request_fd) in requests {
// Only record packages that have services
if !request_fd.service.is_empty() {
packages.insert(request_module.clone(), request_fd.package().to_string());
}
let buf = modules
.entry(request_module.clone())
.or_insert_with(String::new);
CodeGenerator::generate(self, &message_graph, &extern_paths, request_fd, buf);
if buf.is_empty() {
// Did not generate any code, remove from list to avoid inclusion in include file or output file list
modules.remove(&request_module);
}
}
if let Some(ref mut service_generator) = self.service_generator {
for (module, package) in packages {
let buf = modules.get_mut(&module).unwrap();
service_generator.finalize_package(&package, buf);
}
}
if self.fmt {
self.fmt_modules(&mut modules);
}
Ok(modules)
}