1 use std::convert::Infallible;
2 
3 use crate::gen::rust::rel_path::RustRelativePath;
4 
5 /// Field visibility.
6 pub(crate) enum Visibility {
7     Public,
8     Default,
9     Path(RustRelativePath),
10 }
11 
12 pub(crate) struct CodeWriter<'a> {
13     writer: &'a mut String,
14     indent: String,
15 }
16 
17 impl<'a> CodeWriter<'a> {
new(writer: &'a mut String) -> CodeWriter<'a>18     pub(crate) fn new(writer: &'a mut String) -> CodeWriter<'a> {
19         CodeWriter {
20             writer,
21             indent: "".to_string(),
22         }
23     }
24 
with_no_error(f: impl FnOnce(&mut CodeWriter)) -> String25     pub(crate) fn with_no_error(f: impl FnOnce(&mut CodeWriter)) -> String {
26         Self::with_impl::<Infallible, _>(|w| Ok(f(w))).unwrap_or_else(|e| match e {})
27     }
28 
with<F>(f: F) -> anyhow::Result<String> where F: FnOnce(&mut CodeWriter) -> anyhow::Result<()>,29     pub(crate) fn with<F>(f: F) -> anyhow::Result<String>
30     where
31         F: FnOnce(&mut CodeWriter) -> anyhow::Result<()>,
32     {
33         Self::with_impl(f)
34     }
35 
with_impl<E, F>(f: F) -> Result<String, E> where F: FnOnce(&mut CodeWriter) -> Result<(), E>,36     fn with_impl<E, F>(f: F) -> Result<String, E>
37     where
38         F: FnOnce(&mut CodeWriter) -> Result<(), E>,
39     {
40         let mut writer = String::new();
41         {
42             let mut cw = CodeWriter::new(&mut writer);
43             f(&mut cw)?;
44         }
45         Ok(writer)
46     }
47 
write_line<S: AsRef<str>>(&mut self, line: S)48     pub(crate) fn write_line<S: AsRef<str>>(&mut self, line: S) {
49         if line.as_ref().is_empty() {
50             self.writer.push_str("\n");
51         } else {
52             let s: String = [self.indent.as_ref(), line.as_ref(), "\n"].concat();
53             self.writer.push_str(&s);
54         }
55     }
56 
_write_text(&mut self, text: &str)57     pub(crate) fn _write_text(&mut self, text: &str) {
58         for line in text.lines() {
59             self.write_line(line);
60         }
61     }
62 
write_generated_by(&mut self, pkg: &str, version: &str, parser: &str)63     pub(crate) fn write_generated_by(&mut self, pkg: &str, version: &str, parser: &str) {
64         self.write_line(format!(
65             "// This file is generated by {pkg} {version}. Do not edit",
66             pkg = pkg,
67             version = version
68         ));
69         self.write_line(format!(
70             "// .proto file is parsed by {parser}",
71             parser = parser
72         ));
73         self.write_generated_common();
74     }
75 
write_generated_common(&mut self)76     fn write_generated_common(&mut self) {
77         // https://secure.phabricator.com/T784
78         self.write_line(&format!("// {}generated", "@"));
79 
80         self.write_line("");
81         self.comment("https://github.com/rust-lang/rust-clippy/issues/702");
82         self.write_line("#![allow(unknown_lints)]");
83         self.write_line("#![allow(clippy::all)]");
84         self.write_line("");
85         self.write_line("#![allow(unused_attributes)]");
86         self.write_line("#![cfg_attr(rustfmt, rustfmt::skip)]");
87         self.write_line("");
88         self.write_line("#![allow(box_pointers)]");
89         self.write_line("#![allow(dead_code)]");
90         self.write_line("#![allow(missing_docs)]");
91         self.write_line("#![allow(non_camel_case_types)]");
92         self.write_line("#![allow(non_snake_case)]");
93         self.write_line("#![allow(non_upper_case_globals)]");
94         self.write_line("#![allow(trivial_casts)]");
95         self.write_line("#![allow(unused_results)]");
96         self.write_line("#![allow(unused_mut)]");
97     }
98 
unimplemented(&mut self)99     pub(crate) fn unimplemented(&mut self) {
100         self.write_line(format!("unimplemented!();"));
101     }
102 
indented<F>(&mut self, cb: F) where F: FnOnce(&mut CodeWriter),103     pub(crate) fn indented<F>(&mut self, cb: F)
104     where
105         F: FnOnce(&mut CodeWriter),
106     {
107         cb(&mut CodeWriter {
108             writer: self.writer,
109             indent: format!("{}    ", self.indent),
110         });
111     }
112 
113     #[allow(dead_code)]
commented<F>(&mut self, cb: F) where F: Fn(&mut CodeWriter),114     pub(crate) fn commented<F>(&mut self, cb: F)
115     where
116         F: Fn(&mut CodeWriter),
117     {
118         cb(&mut CodeWriter {
119             writer: self.writer,
120             indent: format!("// {}", self.indent),
121         });
122     }
123 
pub_const(&mut self, name: &str, field_type: &str, init: &str)124     pub(crate) fn pub_const(&mut self, name: &str, field_type: &str, init: &str) {
125         self.write_line(&format!("pub const {}: {} = {};", name, field_type, init));
126     }
127 
lazy_static(&mut self, name: &str, ty: &str, protobuf_crate_path: &str)128     pub(crate) fn lazy_static(&mut self, name: &str, ty: &str, protobuf_crate_path: &str) {
129         self.write_line(&format!(
130             "static {}: {}::rt::Lazy<{}> = {}::rt::Lazy::new();",
131             name, protobuf_crate_path, ty, protobuf_crate_path,
132         ));
133     }
134 
lazy_static_decl_get_simple( &mut self, name: &str, ty: &str, init: &str, protobuf_crate_path: &str, )135     pub(crate) fn lazy_static_decl_get_simple(
136         &mut self,
137         name: &str,
138         ty: &str,
139         init: &str,
140         protobuf_crate_path: &str,
141     ) {
142         self.lazy_static(name, ty, protobuf_crate_path);
143         self.write_line(&format!("{}.get({})", name, init));
144     }
145 
lazy_static_decl_get( &mut self, name: &str, ty: &str, protobuf_crate_path: &str, init: impl FnOnce(&mut CodeWriter), )146     pub(crate) fn lazy_static_decl_get(
147         &mut self,
148         name: &str,
149         ty: &str,
150         protobuf_crate_path: &str,
151         init: impl FnOnce(&mut CodeWriter),
152     ) {
153         self.lazy_static(name, ty, protobuf_crate_path);
154         self.block(&format!("{}.get(|| {{", name), "})", init);
155     }
156 
block<F>(&mut self, first_line: &str, last_line: &str, cb: F) where F: FnOnce(&mut CodeWriter),157     pub(crate) fn block<F>(&mut self, first_line: &str, last_line: &str, cb: F)
158     where
159         F: FnOnce(&mut CodeWriter),
160     {
161         self.write_line(first_line);
162         self.indented(cb);
163         self.write_line(last_line);
164     }
165 
expr_block<F>(&mut self, prefix: &str, cb: F) where F: FnOnce(&mut CodeWriter),166     pub(crate) fn expr_block<F>(&mut self, prefix: &str, cb: F)
167     where
168         F: FnOnce(&mut CodeWriter),
169     {
170         self.block(&format!("{} {{", prefix), "}", cb);
171     }
172 
stmt_block<S: AsRef<str>, F>(&mut self, prefix: S, cb: F) where F: FnOnce(&mut CodeWriter),173     pub(crate) fn stmt_block<S: AsRef<str>, F>(&mut self, prefix: S, cb: F)
174     where
175         F: FnOnce(&mut CodeWriter),
176     {
177         self.block(&format!("{} {{", prefix.as_ref()), "};", cb);
178     }
179 
impl_self_block<S: AsRef<str>, F>(&mut self, name: S, cb: F) where F: Fn(&mut CodeWriter),180     pub(crate) fn impl_self_block<S: AsRef<str>, F>(&mut self, name: S, cb: F)
181     where
182         F: Fn(&mut CodeWriter),
183     {
184         self.expr_block(&format!("impl {}", name.as_ref()), cb);
185     }
186 
impl_for_block<S1: AsRef<str>, S2: AsRef<str>, F>( &mut self, tr: S1, ty: S2, cb: F, ) where F: Fn(&mut CodeWriter),187     pub(crate) fn impl_for_block<S1: AsRef<str>, S2: AsRef<str>, F>(
188         &mut self,
189         tr: S1,
190         ty: S2,
191         cb: F,
192     ) where
193         F: Fn(&mut CodeWriter),
194     {
195         self.impl_args_for_block(&[], tr.as_ref(), ty.as_ref(), cb);
196     }
197 
impl_args_for_block<F>(&mut self, args: &[&str], tr: &str, ty: &str, cb: F) where F: Fn(&mut CodeWriter),198     pub(crate) fn impl_args_for_block<F>(&mut self, args: &[&str], tr: &str, ty: &str, cb: F)
199     where
200         F: Fn(&mut CodeWriter),
201     {
202         let args_str = if args.is_empty() {
203             "".to_owned()
204         } else {
205             format!("<{}>", args.join(", "))
206         };
207         self.expr_block(&format!("impl{} {} for {}", args_str, tr, ty), cb);
208     }
209 
pub_struct<S: AsRef<str>, F>(&mut self, name: S, cb: F) where F: Fn(&mut CodeWriter),210     pub(crate) fn pub_struct<S: AsRef<str>, F>(&mut self, name: S, cb: F)
211     where
212         F: Fn(&mut CodeWriter),
213     {
214         self.expr_block(&format!("pub struct {}", name.as_ref()), cb);
215     }
216 
pub_enum<F>(&mut self, name: &str, cb: F) where F: Fn(&mut CodeWriter),217     pub(crate) fn pub_enum<F>(&mut self, name: &str, cb: F)
218     where
219         F: Fn(&mut CodeWriter),
220     {
221         self.expr_block(&format!("pub enum {}", name), cb);
222     }
223 
field_entry(&mut self, name: &str, value: &str)224     pub(crate) fn field_entry(&mut self, name: &str, value: &str) {
225         self.write_line(&format!("{}: {},", name, value));
226     }
227 
field_decl(&mut self, name: &str, field_type: &str)228     pub(crate) fn field_decl(&mut self, name: &str, field_type: &str) {
229         self.write_line(&format!("{}: {},", name, field_type));
230     }
231 
pub_field_decl(&mut self, name: &str, field_type: &str)232     pub(crate) fn pub_field_decl(&mut self, name: &str, field_type: &str) {
233         self.write_line(&format!("pub {}: {},", name, field_type));
234     }
235 
field_decl_vis(&mut self, vis: Visibility, name: &str, field_type: &str)236     pub(crate) fn field_decl_vis(&mut self, vis: Visibility, name: &str, field_type: &str) {
237         match vis {
238             Visibility::Public => self.pub_field_decl(name, field_type),
239             Visibility::Default => self.field_decl(name, field_type),
240             Visibility::Path(..) => unimplemented!(),
241         }
242     }
243 
derive(&mut self, derive: &[&str])244     pub(crate) fn derive(&mut self, derive: &[&str]) {
245         let v: Vec<String> = derive.iter().map(|&s| s.to_string()).collect();
246         self.write_line(&format!("#[derive({})]", v.join(",")));
247     }
248 
allow(&mut self, what: &[&str])249     pub(crate) fn allow(&mut self, what: &[&str]) {
250         let v: Vec<String> = what.iter().map(|&s| s.to_string()).collect();
251         self.write_line(&format!("#[allow({})]", v.join(",")));
252     }
253 
comment(&mut self, comment: &str)254     pub(crate) fn comment(&mut self, comment: &str) {
255         if comment.is_empty() {
256             self.write_line("//");
257         } else {
258             self.write_line(&format!("// {}", comment));
259         }
260     }
261 
documentation(&mut self, comment: &str)262     fn documentation(&mut self, comment: &str) {
263         if comment.is_empty() {
264             self.write_line("///");
265         } else {
266             self.write_line(&format!("/// {}", comment));
267         }
268     }
269 
mod_doc(&mut self, comment: &str)270     pub(crate) fn mod_doc(&mut self, comment: &str) {
271         if comment.is_empty() {
272             self.write_line("//!");
273         } else {
274             self.write_line(&format!("//! {}", comment));
275         }
276     }
277 
278     /// Writes the documentation of the given path.
279     ///
280     /// Protobuf paths are defined in proto/google/protobuf/descriptor.proto,
281     /// in the `SourceCodeInfo` message.
282     ///
283     /// For example, say we have a file like:
284     ///
285     /// ```ignore
286     /// message Foo {
287     ///   optional string foo = 1;
288     /// }
289     /// ```
290     ///
291     /// Let's look at just the field definition. We have the following paths:
292     ///
293     /// ```ignore
294     /// path               represents
295     /// [ 4, 0, 2, 0 ]     The whole field definition.
296     /// [ 4, 0, 2, 0, 4 ]  The label (optional).
297     /// [ 4, 0, 2, 0, 5 ]  The type (string).
298     /// [ 4, 0, 2, 0, 1 ]  The name (foo).
299     /// [ 4, 0, 2, 0, 3 ]  The number (1).
300     /// ```
301     ///
302     /// The `4`s can be obtained using simple introspection:
303     ///
304     /// ```
305     /// use protobuf::descriptor::FileDescriptorProto;
306     /// use protobuf::reflect::MessageDescriptor;
307     ///
308     /// let id = MessageDescriptor::for_type::<FileDescriptorProto>()
309     ///     .field_by_name("message_type")
310     ///     .expect("`message_type` must exist")
311     ///     .proto()
312     ///     .number();
313     ///
314     /// assert_eq!(id, 4);
315     /// ```
316     ///
317     /// The first `0` here means this path refers to the first message.
318     ///
319     /// The `2` then refers to the `field` field on the `DescriptorProto` message.
320     ///
321     /// Then comes another `0` to refer to the first field of the current message.
322     ///
323     /// Etc.
324 
all_documentation( &mut self, info: Option<&protobuf::descriptor::SourceCodeInfo>, path: &[i32], )325     pub(crate) fn all_documentation(
326         &mut self,
327         info: Option<&protobuf::descriptor::SourceCodeInfo>,
328         path: &[i32],
329     ) {
330         let doc = info
331             .map(|v| &v.location)
332             .and_then(|ls| ls.iter().find(|l| l.path == path))
333             .map(|l| l.leading_comments());
334 
335         let lines = doc
336             .iter()
337             .map(|doc| doc.lines())
338             .flatten()
339             .collect::<Vec<_>>();
340 
341         // Skip comments with code blocks to avoid rustdoc trying to compile them.
342         if !lines.iter().any(|line| line.starts_with("    ")) {
343             for doc in &lines {
344                 self.documentation(doc);
345             }
346         }
347     }
348 
fn_block<F>(&mut self, vis: Visibility, sig: &str, cb: F) where F: FnOnce(&mut CodeWriter),349     pub(crate) fn fn_block<F>(&mut self, vis: Visibility, sig: &str, cb: F)
350     where
351         F: FnOnce(&mut CodeWriter),
352     {
353         match vis {
354             Visibility::Public => self.expr_block(&format!("pub fn {}", sig), cb),
355             Visibility::Default => self.expr_block(&format!("fn {}", sig), cb),
356             Visibility::Path(p) if p.is_empty() => self.expr_block(&format!("fn {}", sig), cb),
357             Visibility::Path(p) => self.expr_block(&format!("pub(in {}) fn {}", p, sig), cb),
358         }
359     }
360 
pub_fn<F>(&mut self, sig: &str, cb: F) where F: FnOnce(&mut CodeWriter),361     pub(crate) fn pub_fn<F>(&mut self, sig: &str, cb: F)
362     where
363         F: FnOnce(&mut CodeWriter),
364     {
365         self.fn_block(Visibility::Public, sig, cb);
366     }
367 
def_fn<F>(&mut self, sig: &str, cb: F) where F: Fn(&mut CodeWriter),368     pub(crate) fn def_fn<F>(&mut self, sig: &str, cb: F)
369     where
370         F: Fn(&mut CodeWriter),
371     {
372         self.fn_block(Visibility::Default, sig, cb);
373     }
374 
pub_mod<F>(&mut self, name: &str, cb: F) where F: Fn(&mut CodeWriter),375     pub(crate) fn pub_mod<F>(&mut self, name: &str, cb: F)
376     where
377         F: Fn(&mut CodeWriter),
378     {
379         self.expr_block(&format!("pub mod {}", name), cb)
380     }
381 
while_block<S: AsRef<str>, F>(&mut self, cond: S, cb: F) where F: Fn(&mut CodeWriter),382     pub(crate) fn while_block<S: AsRef<str>, F>(&mut self, cond: S, cb: F)
383     where
384         F: Fn(&mut CodeWriter),
385     {
386         self.expr_block(&format!("while {}", cond.as_ref()), cb);
387     }
388 
389     // if ... { ... }
if_stmt<S: AsRef<str>, F>(&mut self, cond: S, cb: F) where F: FnOnce(&mut CodeWriter),390     pub(crate) fn if_stmt<S: AsRef<str>, F>(&mut self, cond: S, cb: F)
391     where
392         F: FnOnce(&mut CodeWriter),
393     {
394         self.expr_block(&format!("if {}", cond.as_ref()), cb);
395     }
396 
397     // if ... {} else { ... }
if_else_stmt<S: AsRef<str>, F>(&mut self, cond: S, cb: F) where F: Fn(&mut CodeWriter),398     pub(crate) fn if_else_stmt<S: AsRef<str>, F>(&mut self, cond: S, cb: F)
399     where
400         F: Fn(&mut CodeWriter),
401     {
402         self.write_line(&format!("if {} {{", cond.as_ref()));
403         self.write_line("} else {");
404         self.indented(cb);
405         self.write_line("}");
406     }
407 
408     // if let ... = ... { ... }
if_let_stmt<F>(&mut self, decl: &str, expr: &str, cb: F) where F: FnOnce(&mut CodeWriter),409     pub(crate) fn if_let_stmt<F>(&mut self, decl: &str, expr: &str, cb: F)
410     where
411         F: FnOnce(&mut CodeWriter),
412     {
413         self.if_stmt(&format!("let {} = {}", decl, expr), cb);
414     }
415 
416     // if let ... = ... { } else { ... }
if_let_else_stmt<F>(&mut self, decl: &str, expr: &str, cb: F) where F: Fn(&mut CodeWriter),417     pub(crate) fn if_let_else_stmt<F>(&mut self, decl: &str, expr: &str, cb: F)
418     where
419         F: Fn(&mut CodeWriter),
420     {
421         self.if_else_stmt(&format!("let {} = {}", decl, expr), cb);
422     }
423 
for_stmt<S1: AsRef<str>, S2: AsRef<str>, F>(&mut self, over: S1, varn: S2, cb: F) where F: FnOnce(&mut CodeWriter),424     pub(crate) fn for_stmt<S1: AsRef<str>, S2: AsRef<str>, F>(&mut self, over: S1, varn: S2, cb: F)
425     where
426         F: FnOnce(&mut CodeWriter),
427     {
428         self.stmt_block(&format!("for {} in {}", varn.as_ref(), over.as_ref()), cb)
429     }
430 
match_block<S: AsRef<str>, F>(&mut self, value: S, cb: F) where F: FnOnce(&mut CodeWriter),431     pub(crate) fn match_block<S: AsRef<str>, F>(&mut self, value: S, cb: F)
432     where
433         F: FnOnce(&mut CodeWriter),
434     {
435         self.stmt_block(&format!("match {}", value.as_ref()), cb);
436     }
437 
match_expr<S: AsRef<str>, F>(&mut self, value: S, cb: F) where F: Fn(&mut CodeWriter),438     pub(crate) fn match_expr<S: AsRef<str>, F>(&mut self, value: S, cb: F)
439     where
440         F: Fn(&mut CodeWriter),
441     {
442         self.expr_block(&format!("match {}", value.as_ref()), cb);
443     }
444 
case_block<S: AsRef<str>, F>(&mut self, cond: S, cb: F) where F: Fn(&mut CodeWriter),445     pub(crate) fn case_block<S: AsRef<str>, F>(&mut self, cond: S, cb: F)
446     where
447         F: Fn(&mut CodeWriter),
448     {
449         self.block(&format!("{} => {{", cond.as_ref()), "},", cb);
450     }
451 
case_expr<S1: AsRef<str>, S2: AsRef<str>>(&mut self, cond: S1, body: S2)452     pub(crate) fn case_expr<S1: AsRef<str>, S2: AsRef<str>>(&mut self, cond: S1, body: S2) {
453         self.write_line(&format!("{} => {},", cond.as_ref(), body.as_ref()));
454     }
455 }
456