blob: 61ce92f39ebb194af14c25ef036e3dbbcfbfe0ab [file] [log] [blame]
Chih-Hung Hsieh92ff6052020-06-10 20:18:39 -07001// 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/rust-lang/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.lazy_static_protobuf_path(name, ty, "::protobuf")
107 }
108
109 pub fn lazy_static_protobuf_path(&mut self, name: &str, ty: &str, protobuf_crate_path: &str) {
110 self.write_line(&format!(
111 "static mut {}: {}::lazy::Lazy<{}> = {}::lazy::Lazy::INIT;",
112 name, protobuf_crate_path, ty, protobuf_crate_path,
113 ));
114 }
115
116 pub fn lazy_static_decl_get<F>(&mut self, name: &str, ty: &str, init: F)
117 where
118 F: Fn(&mut CodeWriter),
119 {
120 self.lazy_static(name, ty);
121 self.unsafe_expr(|w| {
122 w.write_line(&format!("{}.get(|| {{", name));
123 w.indented(|w| init(w));
124 w.write_line(&format!("}})"));
125 });
126 }
127
128 pub fn lazy_static_decl_get_simple(&mut self, name: &str, ty: &str, init: &str) {
129 self.lazy_static(name, ty);
130 self.unsafe_expr(|w| {
131 w.write_line(&format!("{}.get({})", name, init));
132 });
133 }
134
135 pub fn block<F>(&mut self, first_line: &str, last_line: &str, cb: F)
136 where
137 F: Fn(&mut CodeWriter),
138 {
139 self.write_line(first_line);
140 self.indented(cb);
141 self.write_line(last_line);
142 }
143
144 pub fn expr_block<F>(&mut self, prefix: &str, cb: F)
145 where
146 F: Fn(&mut CodeWriter),
147 {
148 self.block(&format!("{} {{", prefix), "}", cb);
149 }
150
151 pub fn stmt_block<S: AsRef<str>, F>(&mut self, prefix: S, cb: F)
152 where
153 F: Fn(&mut CodeWriter),
154 {
155 self.block(&format!("{} {{", prefix.as_ref()), "};", cb);
156 }
157
158 pub fn unsafe_expr<F>(&mut self, cb: F)
159 where
160 F: Fn(&mut CodeWriter),
161 {
162 self.expr_block("unsafe", cb);
163 }
164
165 pub fn impl_self_block<S: AsRef<str>, F>(&mut self, name: S, cb: F)
166 where
167 F: Fn(&mut CodeWriter),
168 {
169 self.expr_block(&format!("impl {}", name.as_ref()), cb);
170 }
171
172 pub fn impl_for_block<S1: AsRef<str>, S2: AsRef<str>, F>(&mut self, tr: S1, ty: S2, cb: F)
173 where
174 F: Fn(&mut CodeWriter),
175 {
176 self.impl_args_for_block(&[], tr.as_ref(), ty.as_ref(), cb);
177 }
178
179 pub fn impl_args_for_block<F>(&mut self, args: &[&str], tr: &str, ty: &str, cb: F)
180 where
181 F: Fn(&mut CodeWriter),
182 {
183 let args_str = if args.is_empty() {
184 "".to_owned()
185 } else {
186 format!("<{}>", args.join(", "))
187 };
188 self.expr_block(&format!("impl{} {} for {}", args_str, tr, ty), cb);
189 }
190
191 pub fn unsafe_impl(&mut self, what: &str, for_what: &str) {
192 self.write_line(&format!("unsafe impl {} for {} {{}}", what, for_what));
193 }
194
195 pub fn pub_struct<S: AsRef<str>, F>(&mut self, name: S, cb: F)
196 where
197 F: Fn(&mut CodeWriter),
198 {
199 self.expr_block(&format!("pub struct {}", name.as_ref()), cb);
200 }
201
202 pub fn def_struct<S: AsRef<str>, F>(&mut self, name: S, cb: F)
203 where
204 F: Fn(&mut CodeWriter),
205 {
206 self.expr_block(&format!("struct {}", name.as_ref()), cb);
207 }
208
209 pub fn pub_enum<F>(&mut self, name: &str, cb: F)
210 where
211 F: Fn(&mut CodeWriter),
212 {
213 self.expr_block(&format!("pub enum {}", name), cb);
214 }
215
216 pub fn pub_trait<F>(&mut self, name: &str, cb: F)
217 where
218 F: Fn(&mut CodeWriter),
219 {
220 self.expr_block(&format!("pub trait {}", name), cb);
221 }
222
223 pub fn pub_trait_extend<F>(&mut self, name: &str, extend: &str, cb: F)
224 where
225 F: Fn(&mut CodeWriter),
226 {
227 self.expr_block(&format!("pub trait {} : {}", name, extend), cb);
228 }
229
230 pub fn field_entry(&mut self, name: &str, value: &str) {
231 self.write_line(&format!("{}: {},", name, value));
232 }
233
234 pub fn field_decl(&mut self, name: &str, field_type: &str) {
235 self.write_line(&format!("{}: {},", name, field_type));
236 }
237
238 pub fn pub_field_decl(&mut self, name: &str, field_type: &str) {
239 self.write_line(&format!("pub {}: {},", name, field_type));
240 }
241
242 pub fn field_decl_vis(&mut self, vis: Visibility, name: &str, field_type: &str) {
243 match vis {
244 Visibility::Public => self.pub_field_decl(name, field_type),
245 Visibility::Default => self.field_decl(name, field_type),
246 }
247 }
248
249 pub fn derive(&mut self, derive: &[&str]) {
250 let v: Vec<String> = derive.iter().map(|&s| s.to_string()).collect();
251 self.write_line(&format!("#[derive({})]", v.join(",")));
252 }
253
254 pub fn allow(&mut self, what: &[&str]) {
255 let v: Vec<String> = what.iter().map(|&s| s.to_string()).collect();
256 self.write_line(&format!("#[allow({})]", v.join(",")));
257 }
258
259 pub fn comment(&mut self, comment: &str) {
260 if comment.is_empty() {
261 self.write_line("//");
262 } else {
263 self.write_line(&format!("// {}", comment));
264 }
265 }
266
267 pub fn fn_def(&mut self, sig: &str) {
268 self.write_line(&format!("fn {};", sig));
269 }
270
271 pub fn fn_block<F>(&mut self, public: bool, sig: &str, cb: F)
272 where
273 F: Fn(&mut CodeWriter),
274 {
275 if public {
276 self.expr_block(&format!("pub fn {}", sig), cb);
277 } else {
278 self.expr_block(&format!("fn {}", sig), cb);
279 }
280 }
281
282 pub fn pub_fn<F>(&mut self, sig: &str, cb: F)
283 where
284 F: Fn(&mut CodeWriter),
285 {
286 self.fn_block(true, sig, cb);
287 }
288
289 pub fn def_fn<F>(&mut self, sig: &str, cb: F)
290 where
291 F: Fn(&mut CodeWriter),
292 {
293 self.fn_block(false, sig, cb);
294 }
295
296 pub fn def_mod<F>(&mut self, name: &str, cb: F)
297 where
298 F: Fn(&mut CodeWriter),
299 {
300 self.expr_block(&format!("mod {}", name), cb)
301 }
302
303 pub fn pub_mod<F>(&mut self, name: &str, cb: F)
304 where
305 F: Fn(&mut CodeWriter),
306 {
307 self.expr_block(&format!("pub mod {}", name), cb)
308 }
309
310 pub fn while_block<S: AsRef<str>, F>(&mut self, cond: S, cb: F)
311 where
312 F: Fn(&mut CodeWriter),
313 {
314 self.expr_block(&format!("while {}", cond.as_ref()), cb);
315 }
316
317 // if ... { ... }
318 pub fn if_stmt<S: AsRef<str>, F>(&mut self, cond: S, cb: F)
319 where
320 F: Fn(&mut CodeWriter),
321 {
322 self.expr_block(&format!("if {}", cond.as_ref()), cb);
323 }
324
325 // if ... {} else { ... }
326 pub fn if_else_stmt<S: AsRef<str>, F>(&mut self, cond: S, cb: F)
327 where
328 F: Fn(&mut CodeWriter),
329 {
330 self.write_line(&format!("if {} {{", cond.as_ref()));
331 self.write_line("} else {");
332 self.indented(cb);
333 self.write_line("}");
334 }
335
336 // if let ... = ... { ... }
337 pub fn if_let_stmt<F>(&mut self, decl: &str, expr: &str, cb: F)
338 where
339 F: Fn(&mut CodeWriter),
340 {
341 self.if_stmt(&format!("let {} = {}", decl, expr), cb);
342 }
343
344 // if let ... = ... { } else { ... }
345 pub fn if_let_else_stmt<F>(&mut self, decl: &str, expr: &str, cb: F)
346 where
347 F: Fn(&mut CodeWriter),
348 {
349 self.if_else_stmt(&format!("let {} = {}", decl, expr), cb);
350 }
351
352 pub fn for_stmt<S1: AsRef<str>, S2: AsRef<str>, F>(&mut self, over: S1, varn: S2, cb: F)
353 where
354 F: Fn(&mut CodeWriter),
355 {
356 self.stmt_block(&format!("for {} in {}", varn.as_ref(), over.as_ref()), cb)
357 }
358
359 pub fn match_block<S: AsRef<str>, F>(&mut self, value: S, cb: F)
360 where
361 F: Fn(&mut CodeWriter),
362 {
363 self.stmt_block(&format!("match {}", value.as_ref()), cb);
364 }
365
366 pub fn match_expr<S: AsRef<str>, F>(&mut self, value: S, cb: F)
367 where
368 F: Fn(&mut CodeWriter),
369 {
370 self.expr_block(&format!("match {}", value.as_ref()), cb);
371 }
372
373 pub fn case_block<S: AsRef<str>, F>(&mut self, cond: S, cb: F)
374 where
375 F: Fn(&mut CodeWriter),
376 {
377 self.block(&format!("{} => {{", cond.as_ref()), "},", cb);
378 }
379
380 pub fn case_expr<S1: AsRef<str>, S2: AsRef<str>>(&mut self, cond: S1, body: S2) {
381 self.write_line(&format!("{} => {},", cond.as_ref(), body.as_ref()));
382 }
383}