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§

Generates a Rust interface or implementation for a service, writing the result to buf.

Provided Methods§

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?
src/code_generator.rs (line 112)
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();
        }
    }

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?
src/lib.rs (line 1070)
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)
    }

Implementors§