• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use std::collections::HashMap;
2 use std::marker;
3 
4 use crate::descriptor::DescriptorProto;
5 use crate::descriptor::FileDescriptorProto;
6 use crate::descriptorx::find_message_by_rust_name;
7 use crate::reflect::acc::FieldAccessor;
8 use crate::reflect::find_message_or_enum::find_message_or_enum;
9 use crate::reflect::find_message_or_enum::MessageOrEnum;
10 use crate::reflect::FieldDescriptor;
11 use crate::Message;
12 
13 trait MessageFactory: Send + Sync + 'static {
new_instance(&self) -> Box<dyn Message>14     fn new_instance(&self) -> Box<dyn Message>;
15 }
16 
17 struct MessageFactoryImpl<M>(marker::PhantomData<M>);
18 
19 impl<M> MessageFactory for MessageFactoryImpl<M>
20 where
21     M: 'static + Message + Default + Clone + PartialEq,
22 {
new_instance(&self) -> Box<dyn Message>23     fn new_instance(&self) -> Box<dyn Message> {
24         let m: M = Default::default();
25         Box::new(m)
26     }
27 }
28 
29 /// Dynamic message type
30 pub struct MessageDescriptor {
31     full_name: String,
32     proto: &'static DescriptorProto,
33     factory: &'static dyn MessageFactory,
34     fields: Vec<FieldDescriptor>,
35 
36     index_by_name: HashMap<String, usize>,
37     index_by_name_or_json_name: HashMap<String, usize>,
38     index_by_number: HashMap<u32, usize>,
39 }
40 
41 impl MessageDescriptor {
42     /// Get underlying `DescriptorProto` object.
get_proto(&self) -> &DescriptorProto43     pub fn get_proto(&self) -> &DescriptorProto {
44         self.proto
45     }
46 
47     /// Get a message descriptor for given message type
for_type<M: Message>() -> &'static MessageDescriptor48     pub fn for_type<M: Message>() -> &'static MessageDescriptor {
49         M::descriptor_static()
50     }
51 
compute_full_name(package: &str, path_to_package: &str, proto: &DescriptorProto) -> String52     fn compute_full_name(package: &str, path_to_package: &str, proto: &DescriptorProto) -> String {
53         let mut full_name = package.to_owned();
54         if path_to_package.len() != 0 {
55             if full_name.len() != 0 {
56                 full_name.push('.');
57             }
58             full_name.push_str(path_to_package);
59         }
60         if full_name.len() != 0 {
61             full_name.push('.');
62         }
63         full_name.push_str(proto.get_name());
64         full_name
65     }
66 
67     // Non-generic part of `new` is a separate function
68     // to reduce code bloat from multiple instantiations.
new_non_generic_by_rust_name( rust_name: &'static str, fields: Vec<FieldAccessor>, file: &'static FileDescriptorProto, factory: &'static dyn MessageFactory, ) -> MessageDescriptor69     fn new_non_generic_by_rust_name(
70         rust_name: &'static str,
71         fields: Vec<FieldAccessor>,
72         file: &'static FileDescriptorProto,
73         factory: &'static dyn MessageFactory,
74     ) -> MessageDescriptor {
75         let proto = find_message_by_rust_name(file, rust_name);
76 
77         let mut field_proto_by_name = HashMap::new();
78         for field_proto in proto.message.get_field() {
79             field_proto_by_name.insert(field_proto.get_name(), field_proto);
80         }
81 
82         let mut index_by_name = HashMap::new();
83         let mut index_by_name_or_json_name = HashMap::new();
84         let mut index_by_number = HashMap::new();
85 
86         let mut full_name = file.get_package().to_string();
87         if full_name.len() > 0 {
88             full_name.push('.');
89         }
90         full_name.push_str(proto.message.get_name());
91 
92         let fields: Vec<_> = fields
93             .into_iter()
94             .map(|f| {
95                 let proto = *field_proto_by_name.get(&f.name).unwrap();
96                 FieldDescriptor::new(f, proto)
97             })
98             .collect();
99         for (i, f) in fields.iter().enumerate() {
100             assert!(index_by_number
101                 .insert(f.proto().get_number() as u32, i)
102                 .is_none());
103             assert!(index_by_name
104                 .insert(f.proto().get_name().to_owned(), i)
105                 .is_none());
106             assert!(index_by_name_or_json_name
107                 .insert(f.proto().get_name().to_owned(), i)
108                 .is_none());
109 
110             let json_name = f.json_name().to_owned();
111 
112             if json_name != f.proto().get_name() {
113                 assert!(index_by_name_or_json_name.insert(json_name, i).is_none());
114             }
115         }
116         MessageDescriptor {
117             full_name,
118             proto: proto.message,
119             factory,
120             fields,
121             index_by_name,
122             index_by_name_or_json_name,
123             index_by_number,
124         }
125     }
126 
127     // Non-generic part of `new` is a separate function
128     // to reduce code bloat from multiple instantiations.
new_non_generic_by_pb_name( protobuf_name_to_package: &'static str, fields: Vec<FieldAccessor>, file_descriptor_proto: &'static FileDescriptorProto, factory: &'static dyn MessageFactory, ) -> MessageDescriptor129     fn new_non_generic_by_pb_name(
130         protobuf_name_to_package: &'static str,
131         fields: Vec<FieldAccessor>,
132         file_descriptor_proto: &'static FileDescriptorProto,
133         factory: &'static dyn MessageFactory,
134     ) -> MessageDescriptor {
135         let (path_to_package, proto) =
136             match find_message_or_enum(file_descriptor_proto, protobuf_name_to_package) {
137                 (path_to_package, MessageOrEnum::Message(m)) => (path_to_package, m),
138                 (_, MessageOrEnum::Enum(_)) => panic!("not a message"),
139             };
140 
141         let mut field_proto_by_name = HashMap::new();
142         for field_proto in proto.get_field() {
143             field_proto_by_name.insert(field_proto.get_name(), field_proto);
144         }
145 
146         let mut index_by_name = HashMap::new();
147         let mut index_by_name_or_json_name = HashMap::new();
148         let mut index_by_number = HashMap::new();
149 
150         let full_name = MessageDescriptor::compute_full_name(
151             file_descriptor_proto.get_package(),
152             &path_to_package,
153             &proto,
154         );
155         let fields: Vec<_> = fields
156             .into_iter()
157             .map(|f| {
158                 let proto = *field_proto_by_name.get(&f.name).unwrap();
159                 FieldDescriptor::new(f, proto)
160             })
161             .collect();
162 
163         for (i, f) in fields.iter().enumerate() {
164             assert!(index_by_number
165                 .insert(f.proto().get_number() as u32, i)
166                 .is_none());
167             assert!(index_by_name
168                 .insert(f.proto().get_name().to_owned(), i)
169                 .is_none());
170             assert!(index_by_name_or_json_name
171                 .insert(f.proto().get_name().to_owned(), i)
172                 .is_none());
173 
174             let json_name = f.json_name().to_owned();
175 
176             if json_name != f.proto().get_name() {
177                 assert!(index_by_name_or_json_name.insert(json_name, i).is_none());
178             }
179         }
180         MessageDescriptor {
181             full_name,
182             proto,
183             factory,
184             fields,
185             index_by_name,
186             index_by_name_or_json_name,
187             index_by_number,
188         }
189     }
190 
191     /// Construct a new message descriptor.
192     ///
193     /// This operation is called from generated code and rarely
194     /// need to be called directly.
195     #[doc(hidden)]
196     #[deprecated(
197         since = "2.12",
198         note = "Please regenerate .rs files from .proto files to use newer APIs"
199     )]
new<M: 'static + Message + Default + Clone + PartialEq>( rust_name: &'static str, fields: Vec<FieldAccessor>, file: &'static FileDescriptorProto, ) -> MessageDescriptor200     pub fn new<M: 'static + Message + Default + Clone + PartialEq>(
201         rust_name: &'static str,
202         fields: Vec<FieldAccessor>,
203         file: &'static FileDescriptorProto,
204     ) -> MessageDescriptor {
205         let factory = &MessageFactoryImpl(marker::PhantomData::<M>);
206         MessageDescriptor::new_non_generic_by_rust_name(rust_name, fields, file, factory)
207     }
208 
209     /// Construct a new message descriptor.
210     ///
211     /// This operation is called from generated code and rarely
212     /// need to be called directly.
213     #[doc(hidden)]
new_pb_name<M: 'static + Message + Default + Clone + PartialEq>( protobuf_name_to_package: &'static str, fields: Vec<FieldAccessor>, file_descriptor_proto: &'static FileDescriptorProto, ) -> MessageDescriptor214     pub fn new_pb_name<M: 'static + Message + Default + Clone + PartialEq>(
215         protobuf_name_to_package: &'static str,
216         fields: Vec<FieldAccessor>,
217         file_descriptor_proto: &'static FileDescriptorProto,
218     ) -> MessageDescriptor {
219         let factory = &MessageFactoryImpl(marker::PhantomData::<M>);
220         MessageDescriptor::new_non_generic_by_pb_name(
221             protobuf_name_to_package,
222             fields,
223             file_descriptor_proto,
224             factory,
225         )
226     }
227 
228     /// New empty message
new_instance(&self) -> Box<dyn Message>229     pub fn new_instance(&self) -> Box<dyn Message> {
230         self.factory.new_instance()
231     }
232 
233     /// Message name as given in `.proto` file
name(&self) -> &'static str234     pub fn name(&self) -> &'static str {
235         self.proto.get_name()
236     }
237 
238     /// Fully qualified protobuf message name
full_name(&self) -> &str239     pub fn full_name(&self) -> &str {
240         &self.full_name[..]
241     }
242 
243     /// Message field descriptors.
fields(&self) -> &[FieldDescriptor]244     pub fn fields(&self) -> &[FieldDescriptor] {
245         &self.fields
246     }
247 
248     /// Find message field by protobuf field name
249     ///
250     /// Note: protobuf field name might be different for Rust field name.
get_field_by_name<'a>(&'a self, name: &str) -> Option<&'a FieldDescriptor>251     pub fn get_field_by_name<'a>(&'a self, name: &str) -> Option<&'a FieldDescriptor> {
252         let &index = self.index_by_name.get(name)?;
253         Some(&self.fields[index])
254     }
255 
256     /// Find message field by field name or field JSON name
get_field_by_name_or_json_name<'a>(&'a self, name: &str) -> Option<&'a FieldDescriptor>257     pub fn get_field_by_name_or_json_name<'a>(&'a self, name: &str) -> Option<&'a FieldDescriptor> {
258         let &index = self.index_by_name_or_json_name.get(name)?;
259         Some(&self.fields[index])
260     }
261 
262     /// Find message field by field name
get_field_by_number(&self, number: u32) -> Option<&FieldDescriptor>263     pub fn get_field_by_number(&self, number: u32) -> Option<&FieldDescriptor> {
264         let &index = self.index_by_number.get(&number)?;
265         Some(&self.fields[index])
266     }
267 
268     /// Find field by name
269     // TODO: deprecate
field_by_name<'a>(&'a self, name: &str) -> &'a FieldDescriptor270     pub fn field_by_name<'a>(&'a self, name: &str) -> &'a FieldDescriptor {
271         // TODO: clone is weird
272         let &index = self.index_by_name.get(&name.to_string()).unwrap();
273         &self.fields[index]
274     }
275 
276     /// Find field by number
277     // TODO: deprecate
field_by_number<'a>(&'a self, number: u32) -> &'a FieldDescriptor278     pub fn field_by_number<'a>(&'a self, number: u32) -> &'a FieldDescriptor {
279         let &index = self.index_by_number.get(&number).unwrap();
280         &self.fields[index]
281     }
282 }
283