| use std::fmt::Write as _; |
| |
| use protobuf::reflect::FileDescriptor; |
| use protobuf::Message; |
| |
| use crate::gen::code_writer::CodeWriter; |
| use crate::gen::inside::protobuf_crate_path; |
| use crate::gen::paths::proto_path_to_fn_file_descriptor; |
| use crate::gen::rust::snippets::expr_vec_with_capacity_const; |
| use crate::gen::scope::FileScope; |
| use crate::gen::scope::Scope; |
| use crate::gen::scope::WithScope; |
| use crate::Customize; |
| |
| fn escape_byte(s: &mut String, b: u8) { |
| if b == b'\n' { |
| write!(s, "\\n").unwrap(); |
| } else if b == b'\r' { |
| write!(s, "\\r").unwrap(); |
| } else if b == b'\t' { |
| write!(s, "\\t").unwrap(); |
| } else if b == b'\\' || b == b'"' { |
| write!(s, "\\{}", b as char).unwrap(); |
| } else if b == b'\0' { |
| write!(s, "\\0").unwrap(); |
| // ASCII printable except space |
| } else if b > 0x20 && b < 0x7f { |
| write!(s, "{}", b as char).unwrap(); |
| } else { |
| write!(s, "\\x{:02x}", b).unwrap(); |
| } |
| } |
| |
| fn write_generate_file_descriptor( |
| file_descriptor: &FileDescriptor, |
| customize: &Customize, |
| w: &mut CodeWriter, |
| ) { |
| let deps = &file_descriptor.proto().dependency; |
| w.write_line(&format!( |
| "let mut deps = {vec_with_capacity};", |
| vec_with_capacity = expr_vec_with_capacity_const(deps.len()) |
| )); |
| for f in deps { |
| w.write_line(&format!( |
| "deps.push({}().clone());", |
| proto_path_to_fn_file_descriptor(f, customize) |
| )); |
| } |
| |
| let scope = FileScope { file_descriptor }; |
| |
| let messages = scope.find_messages_except_map(); |
| w.write_line(&format!( |
| "let mut messages = {vec_with_capacity};", |
| vec_with_capacity = expr_vec_with_capacity_const(messages.len()) |
| )); |
| for m in &messages { |
| w.write_line(&format!( |
| "messages.push({}::generated_message_descriptor_data());", |
| m.rust_name_to_file(), |
| )); |
| } |
| |
| let enums = scope.find_enums(); |
| w.write_line(&format!( |
| "let mut enums = {};", |
| expr_vec_with_capacity_const(enums.len()) |
| )); |
| for e in &enums { |
| w.write_line(&format!( |
| "enums.push({}::generated_enum_descriptor_data());", |
| e.rust_name_to_file(), |
| )); |
| } |
| |
| w.write_line(&format!( |
| "{}::reflect::GeneratedFileDescriptor::new_generated(", |
| protobuf_crate_path(&customize), |
| )); |
| w.indented(|w| { |
| w.write_line(&format!("file_descriptor_proto(),")); |
| w.write_line(&format!("deps,")); |
| w.write_line(&format!("messages,")); |
| w.write_line(&format!("enums,")); |
| }); |
| w.write_line(")"); |
| } |
| |
| fn write_file_descriptor( |
| file_descriptor: &FileDescriptor, |
| customize: &Customize, |
| w: &mut CodeWriter, |
| ) { |
| w.write_line("/// `FileDescriptor` object which allows dynamic access to files"); |
| w.pub_fn( |
| &format!( |
| "file_descriptor() -> &'static {protobuf_crate}::reflect::FileDescriptor", |
| protobuf_crate = protobuf_crate_path(customize) |
| ), |
| |w| { |
| w.lazy_static( |
| "generated_file_descriptor_lazy", |
| &format!( |
| "{protobuf_crate}::reflect::GeneratedFileDescriptor", |
| protobuf_crate = protobuf_crate_path(customize) |
| ), |
| &format!("{}", protobuf_crate_path(customize)), |
| ); |
| w.lazy_static_decl_get( |
| "file_descriptor", |
| &format!( |
| "{protobuf_crate}::reflect::FileDescriptor", |
| protobuf_crate = protobuf_crate_path(customize) |
| ), |
| &format!("{}", protobuf_crate_path(customize)), |
| |w| { |
| w.block( |
| "let generated_file_descriptor = generated_file_descriptor_lazy.get(|| {", |
| "});", |
| |w| write_generate_file_descriptor(file_descriptor, customize, w), |
| ); |
| w.write_line(&format!( |
| "{protobuf_crate}::reflect::FileDescriptor::new_generated_2(generated_file_descriptor)", |
| protobuf_crate=protobuf_crate_path(&customize), |
| )); |
| } |
| ); |
| }, |
| ); |
| } |
| |
| pub(crate) fn write_file_descriptor_data( |
| file: &FileDescriptor, |
| customize: &Customize, |
| w: &mut CodeWriter, |
| ) { |
| let fdp_bytes = file.proto().write_to_bytes().unwrap(); |
| w.write_line("static file_descriptor_proto_data: &'static [u8] = b\"\\"); |
| w.indented(|w| { |
| const MAX_LINE_LEN: usize = 72; |
| |
| let mut s = String::new(); |
| for &b in &fdp_bytes { |
| let prev_len = s.len(); |
| escape_byte(&mut s, b); |
| let truncate = s.len() > MAX_LINE_LEN; |
| if truncate { |
| s.truncate(prev_len); |
| } |
| if truncate || s.len() == MAX_LINE_LEN { |
| write!(s, "\\").unwrap(); |
| w.write_line(&s); |
| s.clear(); |
| } |
| if truncate { |
| escape_byte(&mut s, b); |
| } |
| } |
| if !s.is_empty() { |
| write!(s, "\\").unwrap(); |
| w.write_line(&s); |
| s.clear(); |
| } |
| }); |
| w.write_line("\";"); |
| w.write_line(""); |
| write_file_descriptor_proto(&customize, w); |
| w.write_line(""); |
| write_file_descriptor(file, &customize, w); |
| } |
| |
| fn write_file_descriptor_proto(customize: &Customize, w: &mut CodeWriter) { |
| w.write_line("/// `FileDescriptorProto` object which was a source for this generated file"); |
| w.def_fn( |
| &format!( |
| "file_descriptor_proto() -> &'static {protobuf_crate}::descriptor::FileDescriptorProto", |
| protobuf_crate=protobuf_crate_path(customize) |
| ), |
| |w| { |
| w.lazy_static_decl_get( |
| "file_descriptor_proto_lazy", |
| &format!( |
| "{protobuf_crate}::descriptor::FileDescriptorProto", |
| protobuf_crate=protobuf_crate_path(customize) |
| ), |
| &format!("{}", protobuf_crate_path(customize)), |
| |w| { |
| w.write_line(&format!( |
| "{protobuf_crate}::Message::parse_from_bytes(file_descriptor_proto_data).unwrap()", |
| protobuf_crate=protobuf_crate_path(customize) |
| )); |
| }, |
| ); |
| }, |
| ); |
| } |
| |
| /// Code to generate call `module::file_descriptor()`. |
| pub(crate) fn file_descriptor_call_expr(scope: &Scope) -> String { |
| format!( |
| "{}()", |
| scope |
| .rust_path_to_file() |
| .to_reverse() |
| .append_ident("file_descriptor".into()) |
| ) |
| } |