1 use std::fmt::Write as _;
2
3 use protobuf::reflect::FileDescriptor;
4 use protobuf::Message;
5
6 use crate::gen::code_writer::CodeWriter;
7 use crate::gen::inside::protobuf_crate_path;
8 use crate::gen::paths::proto_path_to_fn_file_descriptor;
9 use crate::gen::rust::snippets::expr_vec_with_capacity_const;
10 use crate::gen::scope::FileScope;
11 use crate::gen::scope::Scope;
12 use crate::gen::scope::WithScope;
13 use crate::Customize;
14
escape_byte(s: &mut String, b: u8)15 fn escape_byte(s: &mut String, b: u8) {
16 if b == b'\n' {
17 write!(s, "\\n").unwrap();
18 } else if b == b'\r' {
19 write!(s, "\\r").unwrap();
20 } else if b == b'\t' {
21 write!(s, "\\t").unwrap();
22 } else if b == b'\\' || b == b'"' {
23 write!(s, "\\{}", b as char).unwrap();
24 } else if b == b'\0' {
25 write!(s, "\\0").unwrap();
26 // ASCII printable except space
27 } else if b > 0x20 && b < 0x7f {
28 write!(s, "{}", b as char).unwrap();
29 } else {
30 write!(s, "\\x{:02x}", b).unwrap();
31 }
32 }
33
write_generate_file_descriptor( file_descriptor: &FileDescriptor, customize: &Customize, w: &mut CodeWriter, )34 fn write_generate_file_descriptor(
35 file_descriptor: &FileDescriptor,
36 customize: &Customize,
37 w: &mut CodeWriter,
38 ) {
39 let deps = &file_descriptor.proto().dependency;
40 w.write_line(&format!(
41 "let mut deps = {vec_with_capacity};",
42 vec_with_capacity = expr_vec_with_capacity_const(deps.len())
43 ));
44 for f in deps {
45 w.write_line(&format!(
46 "deps.push({}().clone());",
47 proto_path_to_fn_file_descriptor(f, customize)
48 ));
49 }
50
51 let scope = FileScope { file_descriptor };
52
53 let messages = scope.find_messages_except_map();
54 w.write_line(&format!(
55 "let mut messages = {vec_with_capacity};",
56 vec_with_capacity = expr_vec_with_capacity_const(messages.len())
57 ));
58 for m in &messages {
59 w.write_line(&format!(
60 "messages.push({}::generated_message_descriptor_data());",
61 m.rust_name_to_file(),
62 ));
63 }
64
65 let enums = scope.find_enums();
66 w.write_line(&format!(
67 "let mut enums = {};",
68 expr_vec_with_capacity_const(enums.len())
69 ));
70 for e in &enums {
71 w.write_line(&format!(
72 "enums.push({}::generated_enum_descriptor_data());",
73 e.rust_name_to_file(),
74 ));
75 }
76
77 w.write_line(&format!(
78 "{}::reflect::GeneratedFileDescriptor::new_generated(",
79 protobuf_crate_path(&customize),
80 ));
81 w.indented(|w| {
82 w.write_line(&format!("file_descriptor_proto(),"));
83 w.write_line(&format!("deps,"));
84 w.write_line(&format!("messages,"));
85 w.write_line(&format!("enums,"));
86 });
87 w.write_line(")");
88 }
89
write_file_descriptor( file_descriptor: &FileDescriptor, customize: &Customize, w: &mut CodeWriter, )90 fn write_file_descriptor(
91 file_descriptor: &FileDescriptor,
92 customize: &Customize,
93 w: &mut CodeWriter,
94 ) {
95 w.write_line("/// `FileDescriptor` object which allows dynamic access to files");
96 w.pub_fn(
97 &format!(
98 "file_descriptor() -> &'static {protobuf_crate}::reflect::FileDescriptor",
99 protobuf_crate = protobuf_crate_path(customize)
100 ),
101 |w| {
102 w.lazy_static(
103 "generated_file_descriptor_lazy",
104 &format!(
105 "{protobuf_crate}::reflect::GeneratedFileDescriptor",
106 protobuf_crate = protobuf_crate_path(customize)
107 ),
108 &format!("{}", protobuf_crate_path(customize)),
109 );
110 w.lazy_static_decl_get(
111 "file_descriptor",
112 &format!(
113 "{protobuf_crate}::reflect::FileDescriptor",
114 protobuf_crate = protobuf_crate_path(customize)
115 ),
116 &format!("{}", protobuf_crate_path(customize)),
117 |w| {
118 w.block(
119 "let generated_file_descriptor = generated_file_descriptor_lazy.get(|| {",
120 "});",
121 |w| write_generate_file_descriptor(file_descriptor, customize, w),
122 );
123 w.write_line(&format!(
124 "{protobuf_crate}::reflect::FileDescriptor::new_generated_2(generated_file_descriptor)",
125 protobuf_crate=protobuf_crate_path(&customize),
126 ));
127 }
128 );
129 },
130 );
131 }
132
write_file_descriptor_data( file: &FileDescriptor, customize: &Customize, w: &mut CodeWriter, )133 pub(crate) fn write_file_descriptor_data(
134 file: &FileDescriptor,
135 customize: &Customize,
136 w: &mut CodeWriter,
137 ) {
138 let fdp_bytes = file.proto().write_to_bytes().unwrap();
139 w.write_line("static file_descriptor_proto_data: &'static [u8] = b\"\\");
140 w.indented(|w| {
141 const MAX_LINE_LEN: usize = 72;
142
143 let mut s = String::new();
144 for &b in &fdp_bytes {
145 let prev_len = s.len();
146 escape_byte(&mut s, b);
147 let truncate = s.len() > MAX_LINE_LEN;
148 if truncate {
149 s.truncate(prev_len);
150 }
151 if truncate || s.len() == MAX_LINE_LEN {
152 write!(s, "\\").unwrap();
153 w.write_line(&s);
154 s.clear();
155 }
156 if truncate {
157 escape_byte(&mut s, b);
158 }
159 }
160 if !s.is_empty() {
161 write!(s, "\\").unwrap();
162 w.write_line(&s);
163 s.clear();
164 }
165 });
166 w.write_line("\";");
167 w.write_line("");
168 write_file_descriptor_proto(&customize, w);
169 w.write_line("");
170 write_file_descriptor(file, &customize, w);
171 }
172
write_file_descriptor_proto(customize: &Customize, w: &mut CodeWriter)173 fn write_file_descriptor_proto(customize: &Customize, w: &mut CodeWriter) {
174 w.write_line("/// `FileDescriptorProto` object which was a source for this generated file");
175 w.def_fn(
176 &format!(
177 "file_descriptor_proto() -> &'static {protobuf_crate}::descriptor::FileDescriptorProto",
178 protobuf_crate=protobuf_crate_path(customize)
179 ),
180 |w| {
181 w.lazy_static_decl_get(
182 "file_descriptor_proto_lazy",
183 &format!(
184 "{protobuf_crate}::descriptor::FileDescriptorProto",
185 protobuf_crate=protobuf_crate_path(customize)
186 ),
187 &format!("{}", protobuf_crate_path(customize)),
188 |w| {
189 w.write_line(&format!(
190 "{protobuf_crate}::Message::parse_from_bytes(file_descriptor_proto_data).unwrap()",
191 protobuf_crate=protobuf_crate_path(customize)
192 ));
193 },
194 );
195 },
196 );
197 }
198
199 /// Code to generate call `module::file_descriptor()`.
file_descriptor_call_expr(scope: &Scope) -> String200 pub(crate) fn file_descriptor_call_expr(scope: &Scope) -> String {
201 format!(
202 "{}()",
203 scope
204 .rust_path_to_file()
205 .to_reverse()
206 .append_ident("file_descriptor".into())
207 )
208 }
209