1 use std::collections::HashMap;
2
3 use protobuf::descriptor::file_options;
4 use protobuf::descriptor::FileDescriptorProto;
5 use protobuf::reflect::FileDescriptor;
6 use protobuf_parse::ProtoPath;
7
8 use crate::compiler_plugin;
9 use crate::customize::ctx::CustomizeElemCtx;
10 use crate::customize::rustproto_proto::customize_from_rustproto_for_file;
11 use crate::gen::code_writer::CodeWriter;
12 use crate::gen::enums::EnumGen;
13 use crate::gen::extensions::write_extensions;
14 use crate::gen::file_descriptor::write_file_descriptor_data;
15 use crate::gen::inside::protobuf_crate_path;
16 use crate::gen::message::MessageGen;
17 use crate::gen::paths::proto_path_to_rust_mod;
18 use crate::gen::scope::FileScope;
19 use crate::gen::scope::RootScope;
20 use crate::proto_name_to_rs;
21
22 pub(crate) struct GenFileResult {
23 pub(crate) compiler_plugin_result: compiler_plugin::GenResult,
24 pub(crate) mod_name: String,
25 }
26
gen_file( file_descriptor: &FileDescriptor, _files_map: &HashMap<&ProtoPath, &FileDescriptor>, root_scope: &RootScope, parent_customize: &CustomizeElemCtx, parser: &str, ) -> anyhow::Result<GenFileResult>27 pub(crate) fn gen_file(
28 file_descriptor: &FileDescriptor,
29 _files_map: &HashMap<&ProtoPath, &FileDescriptor>,
30 root_scope: &RootScope,
31 parent_customize: &CustomizeElemCtx,
32 parser: &str,
33 ) -> anyhow::Result<GenFileResult> {
34 let lite_runtime_from_builtin_option = file_descriptor
35 .proto()
36 .options
37 .get_or_default()
38 .optimize_for()
39 == file_options::OptimizeMode::LITE_RUNTIME;
40
41 let mut customize_from_proto =
42 customize_from_rustproto_for_file(file_descriptor.proto().options.get_or_default());
43 if customize_from_proto.lite_runtime.is_none()
44 && parent_customize.for_elem.lite_runtime.is_none()
45 {
46 customize_from_proto.lite_runtime = Some(lite_runtime_from_builtin_option);
47 }
48
49 let customize = parent_customize.child(&customize_from_proto, file_descriptor);
50
51 let file_scope = FileScope { file_descriptor };
52 let scope = file_scope.to_scope();
53
54 let lite_runtime = customize.for_elem.lite_runtime.unwrap_or(false);
55
56 let v = CodeWriter::with(|w| {
57 w.write_generated_by("rust-protobuf", "3.2.0", parser);
58
59 w.write_line("");
60 w.write_line(&format!(
61 "//! Generated file from `{}`",
62 file_descriptor.proto().name()
63 ));
64
65 if customize.for_elem.lite_runtime.unwrap_or(false) {
66 w.comment("Generated for lite runtime");
67 }
68
69 if customize.for_elem.inside_protobuf != Some(true) {
70 w.write_line("");
71 w.write_line("/// Generated files are compatible only with the same version");
72 w.write_line("/// of protobuf runtime.");
73 w.write_line(&format!(
74 "const _PROTOBUF_VERSION_CHECK: () = {}::{};",
75 protobuf_crate_path(&customize.for_elem),
76 protobuf::VERSION_IDENT
77 ));
78 }
79
80 static NESTED_TYPE_NUMBER: protobuf::rt::Lazy<i32> = protobuf::rt::Lazy::new();
81 let message_type_number = *NESTED_TYPE_NUMBER.get(|| {
82 protobuf::reflect::MessageDescriptor::for_type::<FileDescriptorProto>()
83 .field_by_name("message_type")
84 .expect("`message_type` must exist")
85 .proto()
86 .number()
87 });
88
89 let mut path = vec![message_type_number, 0];
90 for (id, message) in scope.messages().iter().enumerate() {
91 // ignore map entries, because they are not used in map fields
92 if !message.is_map() {
93 path[1] = id as i32;
94
95 w.write_line("");
96 MessageGen::new(
97 file_descriptor,
98 message,
99 &root_scope,
100 &customize,
101 &path,
102 file_descriptor.proto().source_code_info.as_ref(),
103 )?
104 .write(w)?;
105 }
106 }
107
108 static ENUM_TYPE_NUMBER: protobuf::rt::Lazy<i32> = protobuf::rt::Lazy::new();
109 let enum_type_number = *ENUM_TYPE_NUMBER.get(|| {
110 protobuf::reflect::MessageDescriptor::for_type::<FileDescriptorProto>()
111 .field_by_name("enum_type")
112 .expect("`enum_type` must exist")
113 .proto()
114 .number()
115 });
116
117 let mut path = vec![enum_type_number, 0];
118 for (id, enum_type) in scope.enums().iter().enumerate() {
119 path[1] = id as i32;
120
121 w.write_line("");
122 EnumGen::new(
123 enum_type,
124 &customize,
125 root_scope,
126 &path,
127 file_descriptor.proto().source_code_info.as_ref(),
128 )
129 .write(w);
130 }
131
132 write_extensions(file_descriptor, &root_scope, w, &customize);
133
134 if !lite_runtime {
135 w.write_line("");
136 write_file_descriptor_data(file_descriptor, &customize.for_elem, w);
137 }
138
139 Ok(())
140 })?;
141
142 Ok(GenFileResult {
143 compiler_plugin_result: compiler_plugin::GenResult {
144 name: proto_name_to_rs(file_descriptor.proto().name()),
145 content: v.into_bytes(),
146 },
147 mod_name: proto_path_to_rust_mod(file_descriptor.proto().name()).into_string(),
148 })
149 }
150