use protobuf::descriptor::*; use protobuf::reflect::FileDescriptor; use protobuf_parse::ProtobufAbsPath; use crate::customize::ctx::CustomizeElemCtx; use crate::customize::Customize; use crate::gen::code_writer::CodeWriter; use crate::gen::field::rust_field_name_for_protobuf_field_name; use crate::gen::file_and_mod::FileAndMod; use crate::gen::inside::protobuf_crate_path; use crate::gen::message::RustTypeMessage; use crate::gen::rust::ident_with_path::RustIdentWithPath; use crate::gen::rust::rel_path::RustRelativePath; use crate::gen::rust_types_values::*; use crate::gen::scope::RootScope; struct ExtGen<'a> { file: &'a FileDescriptor, root_scope: &'a RootScope<'a>, field: &'a FieldDescriptorProto, customize: Customize, } impl<'a> ExtGen<'a> { fn extendee_rust_name(&self) -> RustIdentWithPath { type_name_to_rust_relative( &ProtobufAbsPath::from(self.field.extendee()), &FileAndMod { file: self.file.proto().name().to_owned(), relative_mod: RustRelativePath::from("exts"), customize: self.customize.clone(), }, self.root_scope, ) } fn repeated(&self) -> bool { match self.field.label() { field_descriptor_proto::Label::LABEL_REPEATED => true, field_descriptor_proto::Label::LABEL_OPTIONAL => false, field_descriptor_proto::Label::LABEL_REQUIRED => { panic!("required ext field: {}", self.field.name()) } } } fn return_type_gen(&self) -> ProtobufTypeGen { if self.field.has_type_name() { let rust_name_relative = type_name_to_rust_relative( &ProtobufAbsPath::from(self.field.type_name()), &FileAndMod { file: self.file.proto().name().to_owned(), relative_mod: RustRelativePath::from("exts"), customize: self.customize.clone(), }, self.root_scope, ); match self.field.type_() { field_descriptor_proto::Type::TYPE_MESSAGE => { ProtobufTypeGen::Message(RustTypeMessage(rust_name_relative)) } field_descriptor_proto::Type::TYPE_ENUM => { ProtobufTypeGen::EnumOrUnknown(rust_name_relative) } t => panic!("unknown type: {:?}", t), } } else { ProtobufTypeGen::Primitive(self.field.type_(), PrimitiveTypeVariant::Default) } } fn write(&self, w: &mut CodeWriter) { let suffix = if self.repeated() { "ExtFieldRepeated" } else { "ExtFieldOptional" }; let field_type = format!( "{protobuf_crate}::ext::{suffix}", protobuf_crate = protobuf_crate_path(&self.customize) ); w.pub_const( &rust_field_name_for_protobuf_field_name(self.field.name()).to_string(), &format!( "{field_type}<{extendee}, {rust_type}>", extendee=self.extendee_rust_name(), rust_type=self.return_type_gen().protobuf_value(&self.customize), ), &format!( "{field_type}::new({field_number}, {protobuf_crate}::descriptor::field_descriptor_proto::Type::{t:?})", field_number=self.field.number(), protobuf_crate = protobuf_crate_path(&self.customize), t=self.field.type_(), ), ); } } pub(crate) fn write_extensions( file: &FileDescriptor, root_scope: &RootScope, w: &mut CodeWriter, customize: &CustomizeElemCtx, ) { if file.proto().extension.is_empty() { return; } if customize.for_elem.lite_runtime.unwrap_or(false) { w.write_line(""); w.comment("Extension generation with lite runtime is not supported"); return; } w.write_line(""); w.write_line("/// Extension fields"); w.pub_mod("exts", |w| { for field in &file.proto().extension { if field.type_() == field_descriptor_proto::Type::TYPE_GROUP { continue; } w.write_line(""); ExtGen { file, root_scope, field, customize: customize.for_elem.clone(), } .write(w); } }); }