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