protoc_gen_tonic/
lib.rs

1#![doc = include_str!("../README.md")]
2
3use std::str;
4
5use prost::Message;
6use prost_types::compiler::CodeGeneratorRequest;
7use protoc_gen_prost::{Generator, InvalidParameter, ModuleRequestSet, Param, Params};
8use tonic_build::Attributes;
9
10use self::{generator::TonicGenerator, resolver::Resolver};
11
12mod generator;
13mod resolver;
14mod util;
15
16/// Execute the core _Prost!_ generator from a raw [`CodeGeneratorRequest`]
17pub fn execute(raw_request: &[u8]) -> protoc_gen_prost::Result {
18    let request = CodeGeneratorRequest::decode(raw_request)?;
19    let params = request.parameter().parse::<Parameters>()?;
20
21    let module_request_set = ModuleRequestSet::new(
22        request.file_to_generate,
23        request.proto_file,
24        raw_request,
25        params.default_package_filename.as_deref(),
26        params.flat_output_dir,
27    )?;
28
29    let resolver = Resolver::new(params.extern_path, params.compile_well_known_types);
30    let mut generator = TonicGenerator {
31        resolver,
32        generate_server: !params.no_server,
33        generate_client: !params.no_client,
34        generate_transport: !params.no_transport,
35        server_attributes: params.server_attributes,
36        client_attributes: params.client_attributes,
37        emit_package: !params.disable_package_emission,
38        insert_include: !params.no_include,
39    };
40
41    let files = generator.generate(&module_request_set)?;
42
43    Ok(files)
44}
45
46/// Parameters use to configure [`Generator`]s built into `protoc-gen-prost-serde`
47///
48/// [`Generator`]: protoc_gen_prost::generators::Generator
49#[derive(Debug, Default)]
50struct Parameters {
51    default_package_filename: Option<String>,
52    extern_path: Vec<(String, String)>,
53    server_attributes: Attributes,
54    client_attributes: Attributes,
55    compile_well_known_types: bool,
56    disable_package_emission: bool,
57    no_server: bool,
58    no_client: bool,
59    no_transport: bool,
60    no_include: bool,
61    flat_output_dir: bool,
62}
63
64impl str::FromStr for Parameters {
65    type Err = InvalidParameter;
66    fn from_str(s: &str) -> Result<Self, Self::Err> {
67        let mut ret_val = Self::default();
68        for param in Params::from_protoc_plugin_opts(s)? {
69            match param {
70                Param::Parameter {
71                    param: "default_package_filename",
72                }
73                | Param::Value {
74                    param: "default_package_filename",
75                    ..
76                } => ret_val.default_package_filename = param.value().map(|s| s.to_string()),
77                Param::KeyValue {
78                    param: "extern_path",
79                    key: prefix,
80                    value: module,
81                } => ret_val.extern_path.push((prefix.to_string(), module)),
82                Param::Parameter {
83                    param: "compile_well_known_types",
84                }
85                | Param::Value {
86                    param: "compile_well_known_types",
87                    value: "true",
88                } => ret_val.compile_well_known_types = true,
89                Param::Value {
90                    param: "compile_well_known_types",
91                    value: "false",
92                } => (),
93                Param::Parameter {
94                    param: "disable_package_emission",
95                }
96                | Param::Value {
97                    param: "disable_package_emission",
98                    value: "true",
99                } => ret_val.disable_package_emission = true,
100                Param::Value {
101                    param: "disable_package_emission",
102                    value: "false",
103                } => (),
104                Param::Parameter { param: "no_server" }
105                | Param::Value {
106                    param: "no_server",
107                    value: "true",
108                } => ret_val.no_server = true,
109                Param::Value {
110                    param: "no_server",
111                    value: "false",
112                } => (),
113                Param::Parameter { param: "no_client" }
114                | Param::Value {
115                    param: "no_client",
116                    value: "true",
117                } => ret_val.no_client = true,
118                Param::Value {
119                    param: "no_client",
120                    value: "false",
121                } => (),
122                Param::Parameter {
123                    param: "no_transport",
124                }
125                | Param::Value {
126                    param: "no_transport",
127                    value: "true",
128                } => ret_val.no_transport = true,
129                Param::Value {
130                    param: "no_transport",
131                    value: "false",
132                } => (),
133                Param::Parameter {
134                    param: "no_include",
135                }
136                | Param::Value {
137                    param: "no_include",
138                    value: "true",
139                } => ret_val.no_include = true,
140                Param::Value {
141                    param: "no_include",
142                    value: "false",
143                } => (),
144                Param::KeyValue {
145                    param: "client_mod_attribute",
146                    key: prefix,
147                    value: attribute,
148                } => ret_val
149                    .client_attributes
150                    .push_mod(prefix, attribute.replace(r"\,", ",").replace(r"\\", r"\")),
151                Param::KeyValue {
152                    param: "client_attribute",
153                    key: prefix,
154                    value: attribute,
155                } => ret_val
156                    .client_attributes
157                    .push_struct(prefix, attribute.replace(r"\,", ",").replace(r"\\", r"\")),
158                Param::KeyValue {
159                    param: "server_mod_attribute",
160                    key: prefix,
161                    value: attribute,
162                } => ret_val
163                    .server_attributes
164                    .push_mod(prefix, attribute.replace(r"\,", ",").replace(r"\\", r"\")),
165                Param::KeyValue {
166                    param: "server_attribute",
167                    key: prefix,
168                    value: attribute,
169                } => ret_val
170                    .server_attributes
171                    .push_struct(prefix, attribute.replace(r"\,", ",").replace(r"\\", r"\")),
172                Param::Parameter {
173                    param: "flat_output_dir",
174                }
175                | Param::Value {
176                    param: "flat_output_dir",
177                    value: "true",
178                } => ret_val.flat_output_dir = true,
179                Param::Value {
180                    param: "flat_output_dir",
181                    value: "false",
182                } => (),
183                _ => return Err(InvalidParameter::from(param)),
184            }
185        }
186
187        Ok(ret_val)
188    }
189}