1use std::collections::HashMap;
25use std::io::Write;
26
27use protobuf::compiler_plugin;
28use protobuf::descriptor::*;
29use protobuf::descriptorx::*;
30
31struct CodeWriter<'a> {
32 writer: &'a mut (dyn Write + 'a),
33 indent: String,
34}
35
36impl<'a> CodeWriter<'a> {
37 pub fn new(writer: &'a mut dyn Write) -> CodeWriter<'a> {
38 CodeWriter {
39 writer,
40 indent: "".to_string(),
41 }
42 }
43
44 pub fn write_line<S: AsRef<str>>(&mut self, line: S) {
45 (if line.as_ref().is_empty() {
46 self.writer.write_all(b"\n")
47 } else {
48 let s: String = [self.indent.as_ref(), line.as_ref(), "\n"].concat();
49 self.writer.write_all(s.as_bytes())
50 })
51 .unwrap();
52 }
53
54 pub fn write_generated(&mut self) {
55 self.write_line("// This file is generated. Do not edit");
56 self.write_generated_common();
57 }
58
59 fn write_generated_common(&mut self) {
60 self.write_line("// @generated");
62
63 self.write_line("");
64 self.comment("https://github.com/Manishearth/rust-clippy/issues/702");
65 self.write_line("#![allow(unknown_lints)]");
66 self.write_line("#![allow(clippy::all)]");
67 self.write_line("");
68 self.write_line("#![allow(box_pointers)]");
69 self.write_line("#![allow(dead_code)]");
70 self.write_line("#![allow(missing_docs)]");
71 self.write_line("#![allow(non_camel_case_types)]");
72 self.write_line("#![allow(non_snake_case)]");
73 self.write_line("#![allow(non_upper_case_globals)]");
74 self.write_line("#![allow(trivial_casts)]");
75 self.write_line("#![allow(unsafe_code)]");
76 self.write_line("#![allow(unused_imports)]");
77 self.write_line("#![allow(unused_results)]");
78 }
79
80 pub fn indented<F>(&mut self, cb: F)
81 where
82 F: Fn(&mut CodeWriter),
83 {
84 cb(&mut CodeWriter {
85 writer: self.writer,
86 indent: format!("{} ", self.indent),
87 });
88 }
89
90 #[allow(dead_code)]
91 pub fn commented<F>(&mut self, cb: F)
92 where
93 F: Fn(&mut CodeWriter),
94 {
95 cb(&mut CodeWriter {
96 writer: self.writer,
97 indent: format!("// {}", self.indent),
98 });
99 }
100
101 pub fn block<F>(&mut self, first_line: &str, last_line: &str, cb: F)
102 where
103 F: Fn(&mut CodeWriter),
104 {
105 self.write_line(first_line);
106 self.indented(cb);
107 self.write_line(last_line);
108 }
109
110 pub fn expr_block<F>(&mut self, prefix: &str, cb: F)
111 where
112 F: Fn(&mut CodeWriter),
113 {
114 self.block(&format!("{prefix} {{"), "}", cb);
115 }
116
117 pub fn impl_self_block<S: AsRef<str>, F>(&mut self, name: S, cb: F)
118 where
119 F: Fn(&mut CodeWriter),
120 {
121 self.expr_block(&format!("impl {}", name.as_ref()), cb);
122 }
123
124 pub fn pub_struct<S: AsRef<str>, F>(&mut self, name: S, cb: F)
125 where
126 F: Fn(&mut CodeWriter),
127 {
128 self.expr_block(&format!("pub struct {}", name.as_ref()), cb);
129 }
130
131 pub fn pub_trait<F>(&mut self, name: &str, cb: F)
132 where
133 F: Fn(&mut CodeWriter),
134 {
135 self.expr_block(&format!("pub trait {name}"), cb);
136 }
137
138 pub fn field_entry(&mut self, name: &str, value: &str) {
139 self.write_line(&format!("{name}: {value},"));
140 }
141
142 pub fn field_decl(&mut self, name: &str, field_type: &str) {
143 self.write_line(&format!("{name}: {field_type},"));
144 }
145
146 pub fn comment(&mut self, comment: &str) {
147 if comment.is_empty() {
148 self.write_line("//");
149 } else {
150 self.write_line(&format!("// {comment}"));
151 }
152 }
153
154 pub fn fn_block<F>(&mut self, public: bool, sig: &str, cb: F)
155 where
156 F: Fn(&mut CodeWriter),
157 {
158 if public {
159 self.expr_block(&format!("pub fn {sig}"), cb);
160 } else {
161 self.expr_block(&format!("fn {sig}"), cb);
162 }
163 }
164
165 pub fn pub_fn<F>(&mut self, sig: &str, cb: F)
166 where
167 F: Fn(&mut CodeWriter),
168 {
169 self.fn_block(true, sig, cb);
170 }
171}
172
173use super::util::{self, fq_grpc, to_snake_case, MethodType};
174
175struct MethodGen<'a> {
176 proto: &'a MethodDescriptorProto,
177 service_name: String,
178 service_path: String,
179 root_scope: &'a RootScope<'a>,
180}
181
182impl<'a> MethodGen<'a> {
183 fn new(
184 proto: &'a MethodDescriptorProto,
185 service_name: String,
186 service_path: String,
187 root_scope: &'a RootScope<'a>,
188 ) -> MethodGen<'a> {
189 MethodGen {
190 proto,
191 service_name,
192 service_path,
193 root_scope,
194 }
195 }
196
197 fn input(&self) -> String {
198 format!(
199 "super::{}",
200 self.root_scope
201 .find_message(self.proto.get_input_type())
202 .rust_fq_name()
203 )
204 }
205
206 fn output(&self) -> String {
207 format!(
208 "super::{}",
209 self.root_scope
210 .find_message(self.proto.get_output_type())
211 .rust_fq_name()
212 )
213 }
214
215 fn method_type(&self) -> (MethodType, String) {
216 match (
217 self.proto.get_client_streaming(),
218 self.proto.get_server_streaming(),
219 ) {
220 (false, false) => (MethodType::Unary, fq_grpc("MethodType::Unary")),
221 (true, false) => (
222 MethodType::ClientStreaming,
223 fq_grpc("MethodType::ClientStreaming"),
224 ),
225 (false, true) => (
226 MethodType::ServerStreaming,
227 fq_grpc("MethodType::ServerStreaming"),
228 ),
229 (true, true) => (MethodType::Duplex, fq_grpc("MethodType::Duplex")),
230 }
231 }
232
233 fn service_name(&self) -> String {
234 to_snake_case(&self.service_name)
235 }
236
237 fn name(&self) -> String {
238 to_snake_case(self.proto.get_name())
239 }
240
241 fn fq_name(&self) -> String {
242 format!("\"{}/{}\"", self.service_path, &self.proto.get_name())
243 }
244
245 fn const_method_name(&self) -> String {
246 format!(
247 "METHOD_{}_{}",
248 self.service_name().to_uppercase(),
249 self.name().to_uppercase()
250 )
251 }
252
253 fn write_definition(&self, w: &mut CodeWriter) {
254 let head = format!(
255 "const {}: {}<{}, {}> = {} {{",
256 self.const_method_name(),
257 fq_grpc("Method"),
258 self.input(),
259 self.output(),
260 fq_grpc("Method")
261 );
262 let pb_mar = format!(
263 "{} {{ ser: {}, de: {} }}",
264 fq_grpc("Marshaller"),
265 fq_grpc("pb_ser"),
266 fq_grpc("pb_de")
267 );
268 w.block(&head, "};", |w| {
269 w.field_entry("ty", &self.method_type().1);
270 w.field_entry("name", &self.fq_name());
271 w.field_entry("req_mar", &pb_mar);
272 w.field_entry("resp_mar", &pb_mar);
273 });
274 }
275
276 fn unary(&self, method_name: &str) -> String {
278 format!(
279 "{}(&self, req: &{}) -> {}<{}>",
280 method_name,
281 self.input(),
282 fq_grpc("Result"),
283 self.output()
284 )
285 }
286
287 fn unary_opt(&self, method_name: &str) -> String {
288 format!(
289 "{}_opt(&self, req: &{}, opt: {}) -> {}<{}>",
290 method_name,
291 self.input(),
292 fq_grpc("CallOption"),
293 fq_grpc("Result"),
294 self.output()
295 )
296 }
297
298 fn unary_async(&self, method_name: &str) -> String {
299 format!(
300 "{}_async(&self, req: &{}) -> {}<{}<{}>>",
301 method_name,
302 self.input(),
303 fq_grpc("Result"),
304 fq_grpc("ClientUnaryReceiver"),
305 self.output()
306 )
307 }
308
309 fn unary_async_opt(&self, method_name: &str) -> String {
310 format!(
311 "{}_async_opt(&self, req: &{}, opt: {}) -> {}<{}<{}>>",
312 method_name,
313 self.input(),
314 fq_grpc("CallOption"),
315 fq_grpc("Result"),
316 fq_grpc("ClientUnaryReceiver"),
317 self.output()
318 )
319 }
320
321 fn client_streaming(&self, method_name: &str) -> String {
322 format!(
323 "{}(&self) -> {}<({}<{}>, {}<{}>)>",
324 method_name,
325 fq_grpc("Result"),
326 fq_grpc("ClientCStreamSender"),
327 self.input(),
328 fq_grpc("ClientCStreamReceiver"),
329 self.output()
330 )
331 }
332
333 fn client_streaming_opt(&self, method_name: &str) -> String {
334 format!(
335 "{}_opt(&self, opt: {}) -> {}<({}<{}>, {}<{}>)>",
336 method_name,
337 fq_grpc("CallOption"),
338 fq_grpc("Result"),
339 fq_grpc("ClientCStreamSender"),
340 self.input(),
341 fq_grpc("ClientCStreamReceiver"),
342 self.output()
343 )
344 }
345
346 fn server_streaming(&self, method_name: &str) -> String {
347 format!(
348 "{}(&self, req: &{}) -> {}<{}<{}>>",
349 method_name,
350 self.input(),
351 fq_grpc("Result"),
352 fq_grpc("ClientSStreamReceiver"),
353 self.output()
354 )
355 }
356
357 fn server_streaming_opt(&self, method_name: &str) -> String {
358 format!(
359 "{}_opt(&self, req: &{}, opt: {}) -> {}<{}<{}>>",
360 method_name,
361 self.input(),
362 fq_grpc("CallOption"),
363 fq_grpc("Result"),
364 fq_grpc("ClientSStreamReceiver"),
365 self.output()
366 )
367 }
368
369 fn duplex_streaming(&self, method_name: &str) -> String {
370 format!(
371 "{}(&self) -> {}<({}<{}>, {}<{}>)>",
372 method_name,
373 fq_grpc("Result"),
374 fq_grpc("ClientDuplexSender"),
375 self.input(),
376 fq_grpc("ClientDuplexReceiver"),
377 self.output()
378 )
379 }
380
381 fn duplex_streaming_opt(&self, method_name: &str) -> String {
382 format!(
383 "{}_opt(&self, opt: {}) -> {}<({}<{}>, {}<{}>)>",
384 method_name,
385 fq_grpc("CallOption"),
386 fq_grpc("Result"),
387 fq_grpc("ClientDuplexSender"),
388 self.input(),
389 fq_grpc("ClientDuplexReceiver"),
390 self.output()
391 )
392 }
393
394 fn write_client(&self, w: &mut CodeWriter) {
395 let method_name = self.name();
396 match self.method_type().0 {
397 MethodType::Unary => {
399 w.pub_fn(&self.unary_opt(&method_name), |w| {
400 w.write_line(&format!(
401 "self.client.unary_call(&{}, req, opt)",
402 self.const_method_name()
403 ));
404 });
405 w.write_line("");
406
407 w.pub_fn(&self.unary(&method_name), |w| {
408 w.write_line(&format!(
409 "self.{}_opt(req, {})",
410 method_name,
411 fq_grpc("CallOption::default()")
412 ));
413 });
414 w.write_line("");
415
416 w.pub_fn(&self.unary_async_opt(&method_name), |w| {
417 w.write_line(&format!(
418 "self.client.unary_call_async(&{}, req, opt)",
419 self.const_method_name()
420 ));
421 });
422 w.write_line("");
423
424 w.pub_fn(&self.unary_async(&method_name), |w| {
425 w.write_line(&format!(
426 "self.{}_async_opt(req, {})",
427 method_name,
428 fq_grpc("CallOption::default()")
429 ));
430 });
431 }
432
433 MethodType::ClientStreaming => {
435 w.pub_fn(&self.client_streaming_opt(&method_name), |w| {
436 w.write_line(&format!(
437 "self.client.client_streaming(&{}, opt)",
438 self.const_method_name()
439 ));
440 });
441 w.write_line("");
442
443 w.pub_fn(&self.client_streaming(&method_name), |w| {
444 w.write_line(&format!(
445 "self.{}_opt({})",
446 method_name,
447 fq_grpc("CallOption::default()")
448 ));
449 });
450 }
451
452 MethodType::ServerStreaming => {
454 w.pub_fn(&self.server_streaming_opt(&method_name), |w| {
455 w.write_line(&format!(
456 "self.client.server_streaming(&{}, req, opt)",
457 self.const_method_name()
458 ));
459 });
460 w.write_line("");
461
462 w.pub_fn(&self.server_streaming(&method_name), |w| {
463 w.write_line(&format!(
464 "self.{}_opt(req, {})",
465 method_name,
466 fq_grpc("CallOption::default()")
467 ));
468 });
469 }
470
471 MethodType::Duplex => {
473 w.pub_fn(&self.duplex_streaming_opt(&method_name), |w| {
474 w.write_line(&format!(
475 "self.client.duplex_streaming(&{}, opt)",
476 self.const_method_name()
477 ));
478 });
479 w.write_line("");
480
481 w.pub_fn(&self.duplex_streaming(&method_name), |w| {
482 w.write_line(&format!(
483 "self.{}_opt({})",
484 method_name,
485 fq_grpc("CallOption::default()")
486 ));
487 });
488 }
489 };
490 }
491
492 fn write_service(&self, w: &mut CodeWriter) {
493 let req_stream_type = format!("{}<{}>", fq_grpc("RequestStream"), self.input());
494 let (req, req_type, resp_type) = match self.method_type().0 {
495 MethodType::Unary => ("req", self.input(), "UnarySink"),
496 MethodType::ClientStreaming => ("stream", req_stream_type, "ClientStreamingSink"),
497 MethodType::ServerStreaming => ("req", self.input(), "ServerStreamingSink"),
498 MethodType::Duplex => ("stream", req_stream_type, "DuplexSink"),
499 };
500 let sig = format!(
501 "{}(&mut self, ctx: {}, _{}: {}, sink: {}<{}>)",
502 self.name(),
503 fq_grpc("RpcContext"),
504 req,
505 req_type,
506 fq_grpc(resp_type),
507 self.output()
508 );
509 w.fn_block(false, &sig, |w| {
510 w.write_line("grpcio::unimplemented_call!(ctx, sink)");
511 });
512 }
513
514 fn write_bind(&self, w: &mut CodeWriter) {
515 let add = match self.method_type().0 {
516 MethodType::Unary => "add_unary_handler",
517 MethodType::ClientStreaming => "add_client_streaming_handler",
518 MethodType::ServerStreaming => "add_server_streaming_handler",
519 MethodType::Duplex => "add_duplex_streaming_handler",
520 };
521 w.block(
522 &format!(
523 "builder = builder.{}(&{}, move |ctx, req, resp| {{",
524 add,
525 self.const_method_name()
526 ),
527 "});",
528 |w| {
529 w.write_line(&format!("instance.{}(ctx, req, resp)", self.name()));
530 },
531 );
532 }
533}
534
535struct ServiceGen<'a> {
536 proto: &'a ServiceDescriptorProto,
537 methods: Vec<MethodGen<'a>>,
538}
539
540impl<'a> ServiceGen<'a> {
541 fn new(
542 proto: &'a ServiceDescriptorProto,
543 file: &FileDescriptorProto,
544 root_scope: &'a RootScope,
545 ) -> ServiceGen<'a> {
546 let service_path = if file.get_package().is_empty() {
547 format!("/{}", proto.get_name())
548 } else {
549 format!("/{}.{}", file.get_package(), proto.get_name())
550 };
551 let methods = proto
552 .get_method()
553 .iter()
554 .map(|m| {
555 MethodGen::new(
556 m,
557 util::to_camel_case(proto.get_name()),
558 service_path.clone(),
559 root_scope,
560 )
561 })
562 .collect();
563
564 ServiceGen { proto, methods }
565 }
566
567 fn service_name(&self) -> String {
568 util::to_camel_case(self.proto.get_name())
569 }
570
571 fn client_name(&self) -> String {
572 format!("{}Client", self.service_name())
573 }
574
575 fn write_client(&self, w: &mut CodeWriter) {
576 w.write_line("#[derive(Clone)]");
577 w.pub_struct(&self.client_name(), |w| {
578 w.field_decl("pub client", "::grpcio::Client");
582 });
583
584 w.write_line("");
585
586 w.impl_self_block(&self.client_name(), |w| {
587 w.pub_fn("new(channel: ::grpcio::Channel) -> Self", |w| {
588 w.expr_block(&self.client_name(), |w| {
589 w.field_entry("client", "::grpcio::Client::new(channel)");
590 });
591 });
592
593 for method in &self.methods {
594 w.write_line("");
595 method.write_client(w);
596 }
597 w.pub_fn(
598 "spawn<F>(&self, f: F) where F: ::std::future::Future<Output = ()> + Send + 'static",
599 |w| {
600 w.write_line("self.client.spawn(f)");
601 },
602 )
603 });
604 }
605
606 fn write_server(&self, w: &mut CodeWriter) {
607 w.pub_trait(&self.service_name(), |w| {
608 for method in &self.methods {
609 method.write_service(w);
610 }
611 });
612
613 w.write_line("");
614
615 let s = format!(
616 "create_{}<S: {} + Send + Clone + 'static>(s: S) -> {}",
617 to_snake_case(&self.service_name()),
618 self.service_name(),
619 fq_grpc("Service")
620 );
621 w.pub_fn(&s, |w| {
622 w.write_line("let mut builder = ::grpcio::ServiceBuilder::new();");
623 for method in &self.methods[0..self.methods.len() - 1] {
624 w.write_line("let mut instance = s.clone();");
625 method.write_bind(w);
626 }
627
628 w.write_line("let mut instance = s;");
629 self.methods[self.methods.len() - 1].write_bind(w);
630
631 w.write_line("builder.build()");
632 });
633 }
634
635 fn write_method_definitions(&self, w: &mut CodeWriter) {
636 for (i, method) in self.methods.iter().enumerate() {
637 if i != 0 {
638 w.write_line("");
639 }
640
641 method.write_definition(w);
642 }
643 }
644
645 fn write(&self, w: &mut CodeWriter) {
646 self.write_method_definitions(w);
647 w.write_line("");
648 self.write_client(w);
649 w.write_line("");
650 self.write_server(w);
651 }
652}
653
654fn gen_file(
655 file: &FileDescriptorProto,
656 root_scope: &RootScope,
657) -> Option<compiler_plugin::GenResult> {
658 if file.get_service().is_empty() {
659 return None;
660 }
661
662 let base = protobuf::descriptorx::proto_path_to_rust_mod(file.get_name());
663
664 let mut v = Vec::new();
665 {
666 let mut w = CodeWriter::new(&mut v);
667 w.write_generated();
668
669 for service in file.get_service() {
670 w.write_line("");
671 ServiceGen::new(service, file, root_scope).write(&mut w);
672 }
673 }
674
675 Some(compiler_plugin::GenResult {
676 name: base + "_grpc.rs",
677 content: v,
678 })
679}
680
681pub fn gen(
682 file_descriptors: &[FileDescriptorProto],
683 files_to_generate: &[String],
684) -> Vec<compiler_plugin::GenResult> {
685 let files_map: HashMap<&str, &FileDescriptorProto> =
686 file_descriptors.iter().map(|f| (f.get_name(), f)).collect();
687
688 let root_scope = RootScope { file_descriptors };
689
690 let mut results = Vec::new();
691
692 for file_name in files_to_generate {
693 let file = files_map[&file_name[..]];
694
695 if file.get_service().is_empty() {
696 continue;
697 }
698
699 results.extend(gen_file(file, &root_scope).into_iter());
700 }
701
702 results
703}
704
705pub fn protoc_gen_grpc_rust_main() {
706 compiler_plugin::plugin_main(gen);
707}