use std::collections::HashMap; use protobuf::descriptor::file_options; use protobuf::descriptor::FileDescriptorProto; use protobuf::reflect::FileDescriptor; use protobuf_parse::ProtoPath; use crate::compiler_plugin; use crate::customize::ctx::CustomizeElemCtx; use crate::customize::rustproto_proto::customize_from_rustproto_for_file; use crate::gen::code_writer::CodeWriter; use crate::gen::enums::EnumGen; use crate::gen::extensions::write_extensions; use crate::gen::file_descriptor::write_file_descriptor_data; use crate::gen::inside::protobuf_crate_path; use crate::gen::message::MessageGen; use crate::gen::paths::proto_path_to_rust_mod; use crate::gen::scope::FileScope; use crate::gen::scope::RootScope; use crate::proto_name_to_rs; pub(crate) struct GenFileResult { pub(crate) compiler_plugin_result: compiler_plugin::GenResult, pub(crate) mod_name: String, } pub(crate) fn gen_file( file_descriptor: &FileDescriptor, _files_map: &HashMap<&ProtoPath, &FileDescriptor>, root_scope: &RootScope, parent_customize: &CustomizeElemCtx, parser: &str, ) -> anyhow::Result { let lite_runtime_from_builtin_option = file_descriptor .proto() .options .get_or_default() .optimize_for() == file_options::OptimizeMode::LITE_RUNTIME; let mut customize_from_proto = customize_from_rustproto_for_file(file_descriptor.proto().options.get_or_default()); if customize_from_proto.lite_runtime.is_none() && parent_customize.for_elem.lite_runtime.is_none() { customize_from_proto.lite_runtime = Some(lite_runtime_from_builtin_option); } let customize = parent_customize.child(&customize_from_proto, file_descriptor); let file_scope = FileScope { file_descriptor }; let scope = file_scope.to_scope(); let lite_runtime = customize.for_elem.lite_runtime.unwrap_or(false); let v = CodeWriter::with(|w| { w.write_generated_by("rust-protobuf", "3.2.0", parser); w.write_line(""); w.write_line(&format!( "//! Generated file from `{}`", file_descriptor.proto().name() )); if customize.for_elem.lite_runtime.unwrap_or(false) { w.comment("Generated for lite runtime"); } if customize.for_elem.inside_protobuf != Some(true) { w.write_line(""); w.write_line("/// Generated files are compatible only with the same version"); w.write_line("/// of protobuf runtime."); w.write_line(&format!( "const _PROTOBUF_VERSION_CHECK: () = {}::{};", protobuf_crate_path(&customize.for_elem), protobuf::VERSION_IDENT )); } static NESTED_TYPE_NUMBER: protobuf::rt::Lazy = protobuf::rt::Lazy::new(); let message_type_number = *NESTED_TYPE_NUMBER.get(|| { protobuf::reflect::MessageDescriptor::for_type::() .field_by_name("message_type") .expect("`message_type` must exist") .proto() .number() }); let mut path = vec![message_type_number, 0]; for (id, message) in scope.messages().iter().enumerate() { // ignore map entries, because they are not used in map fields if !message.is_map() { path[1] = id as i32; w.write_line(""); MessageGen::new( file_descriptor, message, &root_scope, &customize, &path, file_descriptor.proto().source_code_info.as_ref(), )? .write(w)?; } } static ENUM_TYPE_NUMBER: protobuf::rt::Lazy = protobuf::rt::Lazy::new(); let enum_type_number = *ENUM_TYPE_NUMBER.get(|| { protobuf::reflect::MessageDescriptor::for_type::() .field_by_name("enum_type") .expect("`enum_type` must exist") .proto() .number() }); let mut path = vec![enum_type_number, 0]; for (id, enum_type) in scope.enums().iter().enumerate() { path[1] = id as i32; w.write_line(""); EnumGen::new( enum_type, &customize, root_scope, &path, file_descriptor.proto().source_code_info.as_ref(), ) .write(w); } write_extensions(file_descriptor, &root_scope, w, &customize); if !lite_runtime { w.write_line(""); write_file_descriptor_data(file_descriptor, &customize.for_elem, w); } Ok(()) })?; Ok(GenFileResult { compiler_plugin_result: compiler_plugin::GenResult { name: proto_name_to_rs(file_descriptor.proto().name()), content: v.into_bytes(), }, mod_name: proto_path_to_rust_mod(file_descriptor.proto().name()).into_string(), }) }