• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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