nrc_protobuf_codegen/
code_writer.rs

1// TODO: used by grpc-rust, should move it into separate crate.
2#![doc(hidden)]
3
4use std::io::Write;
5
6/// Field visibility.
7pub enum Visibility {
8    Public,
9    Default,
10}
11
12pub struct CodeWriter<'a> {
13    writer: &'a mut (dyn Write + 'a),
14    indent: String,
15}
16
17impl<'a> CodeWriter<'a> {
18    pub fn new(writer: &'a mut dyn Write) -> CodeWriter<'a> {
19        CodeWriter {
20            writer: writer,
21            indent: "".to_string(),
22        }
23    }
24
25    pub fn write_line<S: AsRef<str>>(&mut self, line: S) {
26        (if line.as_ref().is_empty() {
27            self.writer.write_all("\n".as_bytes())
28        } else {
29            let s: String = [self.indent.as_ref(), line.as_ref(), "\n"].concat();
30            self.writer.write_all(s.as_bytes())
31        })
32        .unwrap();
33    }
34
35    pub fn write_generated(&mut self) {
36        self.write_line("// This file is generated. Do not edit");
37        self.write_generated_common();
38    }
39
40    pub fn write_generated_by(&mut self, pkg: &str, version: &str) {
41        self.write_line(format!(
42            "// This file is generated by {pkg} {version}. Do not edit",
43            pkg = pkg,
44            version = version
45        ));
46        self.write_generated_common();
47    }
48
49    fn write_generated_common(&mut self) {
50        // https://secure.phabricator.com/T784
51        self.write_line("// @generated");
52
53        self.write_line("");
54        self.comment("https://github.com/Manishearth/rust-clippy/issues/702");
55        self.write_line("#![allow(unknown_lints)]");
56        self.write_line("#![allow(clippy::all)]");
57        self.write_line("");
58        self.write_line("#![cfg_attr(rustfmt, rustfmt_skip)]");
59        self.write_line("");
60        self.write_line("#![allow(box_pointers)]");
61        self.write_line("#![allow(dead_code)]");
62        self.write_line("#![allow(missing_docs)]");
63        self.write_line("#![allow(non_camel_case_types)]");
64        self.write_line("#![allow(non_snake_case)]");
65        self.write_line("#![allow(non_upper_case_globals)]");
66        self.write_line("#![allow(trivial_casts)]");
67        self.write_line("#![allow(unsafe_code)]");
68        self.write_line("#![allow(unused_imports)]");
69        self.write_line("#![allow(unused_results)]");
70    }
71
72    pub fn todo(&mut self, message: &str) {
73        self.write_line(format!("panic!(\"TODO: {}\");", message));
74    }
75
76    pub fn unimplemented(&mut self) {
77        self.write_line(format!("unimplemented!();"));
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 pub_const(&mut self, name: &str, field_type: &str, init: &str) {
102        self.write_line(&format!("pub const {}: {} = {};", name, field_type, init));
103    }
104
105    pub fn lazy_static(&mut self, name: &str, ty: &str) {
106        self.stmt_block(
107            &format!(
108                "static mut {}: ::protobuf::lazy::Lazy<{}> = ::protobuf::lazy::Lazy",
109                name, ty
110            ),
111            |w| {
112                w.field_entry("lock", "::protobuf::lazy::ONCE_INIT");
113                w.field_entry("ptr", &format!("0 as *const {}", ty));
114            },
115        );
116    }
117
118    pub fn lazy_static_protobuf_path(&mut self, name: &str, ty: &str, protobuf_crate_path: &str) {
119        self.stmt_block(
120            &format!(
121                "static mut {}: {}::lazy::Lazy<{}> = ::protobuf::lazy::Lazy",
122                name, protobuf_crate_path, ty
123            ),
124            |w| {
125                w.field_entry("lock", &format!("{}::lazy::ONCE_INIT", protobuf_crate_path));
126                w.field_entry("ptr", &format!("0 as *const {}", ty));
127            },
128        );
129    }
130
131    pub fn lazy_static_decl_get<F>(&mut self, name: &str, ty: &str, init: F)
132    where
133        F: Fn(&mut CodeWriter),
134    {
135        self.lazy_static(name, ty);
136        self.unsafe_expr(|w| {
137            w.write_line(&format!("{}.get(|| {{", name));
138            w.indented(|w| init(w));
139            w.write_line(&format!("}})"));
140        });
141    }
142
143    pub fn lazy_static_decl_get_simple(&mut self, name: &str, ty: &str, init: &str) {
144        self.lazy_static(name, ty);
145        self.unsafe_expr(|w| {
146            w.write_line(&format!("{}.get({})", name, init));
147        });
148    }
149
150    pub fn block<F>(&mut self, first_line: &str, last_line: &str, cb: F)
151    where
152        F: Fn(&mut CodeWriter),
153    {
154        self.write_line(first_line);
155        self.indented(cb);
156        self.write_line(last_line);
157    }
158
159    pub fn expr_block<F>(&mut self, prefix: &str, cb: F)
160    where
161        F: Fn(&mut CodeWriter),
162    {
163        self.block(&format!("{} {{", prefix), "}", cb);
164    }
165
166    pub fn stmt_block<S: AsRef<str>, F>(&mut self, prefix: S, cb: F)
167    where
168        F: Fn(&mut CodeWriter),
169    {
170        self.block(&format!("{} {{", prefix.as_ref()), "};", cb);
171    }
172
173    pub fn unsafe_expr<F>(&mut self, cb: F)
174    where
175        F: Fn(&mut CodeWriter),
176    {
177        self.expr_block("unsafe", cb);
178    }
179
180    pub 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
187    pub fn impl_for_block<S1: AsRef<str>, S2: AsRef<str>, F>(&mut self, tr: S1, ty: S2, cb: F)
188    where
189        F: Fn(&mut CodeWriter),
190    {
191        self.impl_args_for_block(&[], tr.as_ref(), ty.as_ref(), cb);
192    }
193
194    pub fn impl_args_for_block<F>(&mut self, args: &[&str], tr: &str, ty: &str, cb: F)
195    where
196        F: Fn(&mut CodeWriter),
197    {
198        let args_str = if args.is_empty() {
199            "".to_owned()
200        } else {
201            format!("<{}>", args.join(", "))
202        };
203        self.expr_block(&format!("impl{} {} for {}", args_str, tr, ty), cb);
204    }
205
206    pub fn unsafe_impl(&mut self, what: &str, for_what: &str) {
207        self.write_line(&format!("unsafe impl {} for {} {{}}", what, for_what));
208    }
209
210    pub 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
217    pub fn def_struct<S: AsRef<str>, F>(&mut self, name: S, cb: F)
218    where
219        F: Fn(&mut CodeWriter),
220    {
221        self.expr_block(&format!("struct {}", name.as_ref()), cb);
222    }
223
224    pub fn pub_enum<F>(&mut self, name: &str, cb: F)
225    where
226        F: Fn(&mut CodeWriter),
227    {
228        self.expr_block(&format!("pub enum {}", name), cb);
229    }
230
231    pub fn pub_trait<F>(&mut self, name: &str, cb: F)
232    where
233        F: Fn(&mut CodeWriter),
234    {
235        self.expr_block(&format!("pub trait {}", name), cb);
236    }
237
238    pub fn pub_trait_extend<F>(&mut self, name: &str, extend: &str, cb: F)
239    where
240        F: Fn(&mut CodeWriter),
241    {
242        self.expr_block(&format!("pub trait {} : {}", name, extend), cb);
243    }
244
245    pub fn field_entry(&mut self, name: &str, value: &str) {
246        self.write_line(&format!("{}: {},", name, value));
247    }
248
249    pub fn field_decl(&mut self, name: &str, field_type: &str) {
250        self.write_line(&format!("{}: {},", name, field_type));
251    }
252
253    pub fn pub_field_decl(&mut self, name: &str, field_type: &str) {
254        self.write_line(&format!("pub {}: {},", name, field_type));
255    }
256
257    pub fn field_decl_vis(&mut self, vis: Visibility, name: &str, field_type: &str) {
258        match vis {
259            Visibility::Public => self.pub_field_decl(name, field_type),
260            Visibility::Default => self.field_decl(name, field_type),
261        }
262    }
263
264    pub fn derive(&mut self, derive: &[&str]) {
265        let v: Vec<String> = derive.iter().map(|&s| s.to_string()).collect();
266        self.write_line(&format!("#[derive({})]", v.join(",")));
267    }
268
269    pub fn allow(&mut self, what: &[&str]) {
270        let v: Vec<String> = what.iter().map(|&s| s.to_string()).collect();
271        self.write_line(&format!("#[allow({})]", v.join(",")));
272    }
273
274    pub fn comment(&mut self, comment: &str) {
275        if comment.is_empty() {
276            self.write_line("//");
277        } else {
278            self.write_line(&format!("// {}", comment));
279        }
280    }
281
282    pub fn fn_def(&mut self, sig: &str) {
283        self.write_line(&format!("fn {};", sig));
284    }
285
286    pub fn fn_block<F>(&mut self, public: bool, sig: &str, cb: F)
287    where
288        F: Fn(&mut CodeWriter),
289    {
290        if public {
291            self.expr_block(&format!("pub fn {}", sig), cb);
292        } else {
293            self.expr_block(&format!("fn {}", sig), cb);
294        }
295    }
296
297    pub fn pub_fn<F>(&mut self, sig: &str, cb: F)
298    where
299        F: Fn(&mut CodeWriter),
300    {
301        self.fn_block(true, sig, cb);
302    }
303
304    pub fn def_fn<F>(&mut self, sig: &str, cb: F)
305    where
306        F: Fn(&mut CodeWriter),
307    {
308        self.fn_block(false, sig, cb);
309    }
310
311    pub fn def_mod<F>(&mut self, name: &str, cb: F)
312    where
313        F: Fn(&mut CodeWriter),
314    {
315        self.expr_block(&format!("mod {}", name), cb)
316    }
317
318    pub fn pub_mod<F>(&mut self, name: &str, cb: F)
319    where
320        F: Fn(&mut CodeWriter),
321    {
322        self.expr_block(&format!("pub mod {}", name), cb)
323    }
324
325    pub fn while_block<S: AsRef<str>, F>(&mut self, cond: S, cb: F)
326    where
327        F: Fn(&mut CodeWriter),
328    {
329        self.expr_block(&format!("while {}", cond.as_ref()), cb);
330    }
331
332    // if ... { ... }
333    pub fn if_stmt<S: AsRef<str>, F>(&mut self, cond: S, cb: F)
334    where
335        F: Fn(&mut CodeWriter),
336    {
337        self.expr_block(&format!("if {}", cond.as_ref()), cb);
338    }
339
340    // if ... {} else { ... }
341    pub fn if_else_stmt<S: AsRef<str>, F>(&mut self, cond: S, cb: F)
342    where
343        F: Fn(&mut CodeWriter),
344    {
345        self.write_line(&format!("if {} {{", cond.as_ref()));
346        self.write_line("} else {");
347        self.indented(cb);
348        self.write_line("}");
349    }
350
351    // if let ... = ... { ... }
352    pub fn if_let_stmt<F>(&mut self, decl: &str, expr: &str, cb: F)
353    where
354        F: Fn(&mut CodeWriter),
355    {
356        self.if_stmt(&format!("let {} = {}", decl, expr), cb);
357    }
358
359    // if let ... = ... { } else { ... }
360    pub fn if_let_else_stmt<F>(&mut self, decl: &str, expr: &str, cb: F)
361    where
362        F: Fn(&mut CodeWriter),
363    {
364        self.if_else_stmt(&format!("let {} = {}", decl, expr), cb);
365    }
366
367    pub fn for_stmt<S1: AsRef<str>, S2: AsRef<str>, F>(&mut self, over: S1, varn: S2, cb: F)
368    where
369        F: Fn(&mut CodeWriter),
370    {
371        self.stmt_block(&format!("for {} in {}", varn.as_ref(), over.as_ref()), cb)
372    }
373
374    pub fn match_block<S: AsRef<str>, F>(&mut self, value: S, cb: F)
375    where
376        F: Fn(&mut CodeWriter),
377    {
378        self.stmt_block(&format!("match {}", value.as_ref()), cb);
379    }
380
381    pub fn match_expr<S: AsRef<str>, F>(&mut self, value: S, cb: F)
382    where
383        F: Fn(&mut CodeWriter),
384    {
385        self.expr_block(&format!("match {}", value.as_ref()), cb);
386    }
387
388    pub fn case_block<S: AsRef<str>, F>(&mut self, cond: S, cb: F)
389    where
390        F: Fn(&mut CodeWriter),
391    {
392        self.block(&format!("{} => {{", cond.as_ref()), "},", cb);
393    }
394
395    pub fn case_expr<S1: AsRef<str>, S2: AsRef<str>>(&mut self, cond: S1, body: S2) {
396        self.write_line(&format!("{} => {},", cond.as_ref(), body.as_ref()));
397    }
398}