blob: 2c8249c36187c977073ed331edd1489ffaa7dc71 [file] [log] [blame]
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())
)
}