diff options
Diffstat (limited to 'src/gen/file_descriptor.rs')
-rw-r--r-- | src/gen/file_descriptor.rs | 208 |
1 files changed, 208 insertions, 0 deletions
diff --git a/src/gen/file_descriptor.rs b/src/gen/file_descriptor.rs new file mode 100644 index 0000000..2c8249c --- /dev/null +++ b/src/gen/file_descriptor.rs @@ -0,0 +1,208 @@ +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()) + ) +} |