1 use protobuf::descriptor::*;
2 use protobuf::reflect::FileDescriptor;
3 use protobuf_parse::ProtobufAbsPath;
4
5 use crate::customize::ctx::CustomizeElemCtx;
6 use crate::customize::Customize;
7 use crate::gen::code_writer::CodeWriter;
8 use crate::gen::field::rust_field_name_for_protobuf_field_name;
9 use crate::gen::file_and_mod::FileAndMod;
10 use crate::gen::inside::protobuf_crate_path;
11 use crate::gen::message::RustTypeMessage;
12 use crate::gen::rust::ident_with_path::RustIdentWithPath;
13 use crate::gen::rust::rel_path::RustRelativePath;
14 use crate::gen::rust_types_values::*;
15 use crate::gen::scope::RootScope;
16
17 struct ExtGen<'a> {
18 file: &'a FileDescriptor,
19 root_scope: &'a RootScope<'a>,
20 field: &'a FieldDescriptorProto,
21 customize: Customize,
22 }
23
24 impl<'a> ExtGen<'a> {
extendee_rust_name(&self) -> RustIdentWithPath25 fn extendee_rust_name(&self) -> RustIdentWithPath {
26 type_name_to_rust_relative(
27 &ProtobufAbsPath::from(self.field.extendee()),
28 &FileAndMod {
29 file: self.file.proto().name().to_owned(),
30 relative_mod: RustRelativePath::from("exts"),
31 customize: self.customize.clone(),
32 },
33 self.root_scope,
34 )
35 }
36
repeated(&self) -> bool37 fn repeated(&self) -> bool {
38 match self.field.label() {
39 field_descriptor_proto::Label::LABEL_REPEATED => true,
40 field_descriptor_proto::Label::LABEL_OPTIONAL => false,
41 field_descriptor_proto::Label::LABEL_REQUIRED => {
42 panic!("required ext field: {}", self.field.name())
43 }
44 }
45 }
46
return_type_gen(&self) -> ProtobufTypeGen47 fn return_type_gen(&self) -> ProtobufTypeGen {
48 if self.field.has_type_name() {
49 let rust_name_relative = type_name_to_rust_relative(
50 &ProtobufAbsPath::from(self.field.type_name()),
51 &FileAndMod {
52 file: self.file.proto().name().to_owned(),
53 relative_mod: RustRelativePath::from("exts"),
54 customize: self.customize.clone(),
55 },
56 self.root_scope,
57 );
58 match self.field.type_() {
59 field_descriptor_proto::Type::TYPE_MESSAGE => {
60 ProtobufTypeGen::Message(RustTypeMessage(rust_name_relative))
61 }
62 field_descriptor_proto::Type::TYPE_ENUM => {
63 ProtobufTypeGen::EnumOrUnknown(rust_name_relative)
64 }
65 t => panic!("unknown type: {:?}", t),
66 }
67 } else {
68 ProtobufTypeGen::Primitive(self.field.type_(), PrimitiveTypeVariant::Default)
69 }
70 }
71
write(&self, w: &mut CodeWriter)72 fn write(&self, w: &mut CodeWriter) {
73 let suffix = if self.repeated() {
74 "ExtFieldRepeated"
75 } else {
76 "ExtFieldOptional"
77 };
78 let field_type = format!(
79 "{protobuf_crate}::ext::{suffix}",
80 protobuf_crate = protobuf_crate_path(&self.customize)
81 );
82 w.pub_const(
83 &rust_field_name_for_protobuf_field_name(self.field.name()).to_string(),
84 &format!(
85 "{field_type}<{extendee}, {rust_type}>",
86 extendee=self.extendee_rust_name(),
87 rust_type=self.return_type_gen().protobuf_value(&self.customize),
88 ),
89 &format!(
90 "{field_type}::new({field_number}, {protobuf_crate}::descriptor::field_descriptor_proto::Type::{t:?})",
91 field_number=self.field.number(),
92 protobuf_crate = protobuf_crate_path(&self.customize),
93 t=self.field.type_(),
94 ),
95 );
96 }
97 }
98
write_extensions( file: &FileDescriptor, root_scope: &RootScope, w: &mut CodeWriter, customize: &CustomizeElemCtx, )99 pub(crate) fn write_extensions(
100 file: &FileDescriptor,
101 root_scope: &RootScope,
102 w: &mut CodeWriter,
103 customize: &CustomizeElemCtx,
104 ) {
105 if file.proto().extension.is_empty() {
106 return;
107 }
108
109 if customize.for_elem.lite_runtime.unwrap_or(false) {
110 w.write_line("");
111 w.comment("Extension generation with lite runtime is not supported");
112 return;
113 }
114
115 w.write_line("");
116 w.write_line("/// Extension fields");
117 w.pub_mod("exts", |w| {
118 for field in &file.proto().extension {
119 if field.type_() == field_descriptor_proto::Type::TYPE_GROUP {
120 continue;
121 }
122
123 w.write_line("");
124 ExtGen {
125 file,
126 root_scope,
127 field,
128 customize: customize.for_elem.clone(),
129 }
130 .write(w);
131 }
132 });
133 }
134