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