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
16pub 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#[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}