1 use protobuf::descriptor::DescriptorProto;
2 use protobuf::descriptor::EnumDescriptorProto;
3 use protobuf::descriptor::EnumValueDescriptorProto;
4 use protobuf::descriptor::FieldDescriptorProto;
5 use protobuf::descriptor::FileDescriptorProto;
6 use protobuf::descriptor::OneofDescriptorProto;
7 
8 use crate::field::rust_field_name_for_protobuf_field_name;
9 use crate::file::proto_path_to_rust_mod;
10 use crate::protobuf_name::ProtobufAbsolutePath;
11 use crate::protobuf_name::ProtobufIdent;
12 use crate::protobuf_name::ProtobufRelativePath;
13 use crate::rust;
14 use crate::rust_name::RustIdent;
15 use crate::rust_name::RustIdentWithPath;
16 use crate::syntax::Syntax;
17 
18 pub(crate) struct RootScope<'a> {
19     pub file_descriptors: &'a [FileDescriptorProto],
20 }
21 
22 impl<'a> RootScope<'a> {
packages(&'a self) -> Vec<FileScope<'a>>23     fn packages(&'a self) -> Vec<FileScope<'a>> {
24         self.file_descriptors
25             .iter()
26             .map(|fd| FileScope {
27                 file_descriptor: fd,
28             })
29             .collect()
30     }
31 
32     // find enum by fully qualified name
_find_enum(&'a self, fqn: &ProtobufAbsolutePath) -> EnumWithScope<'a>33     pub fn _find_enum(&'a self, fqn: &ProtobufAbsolutePath) -> EnumWithScope<'a> {
34         match self.find_message_or_enum(fqn) {
35             MessageOrEnumWithScope::Enum(e) => e,
36             _ => panic!("not an enum: {}", fqn),
37         }
38     }
39 
40     // find message by fully qualified name
find_message(&'a self, fqn: &ProtobufAbsolutePath) -> MessageWithScope<'a>41     pub fn find_message(&'a self, fqn: &ProtobufAbsolutePath) -> MessageWithScope<'a> {
42         match self.find_message_or_enum(fqn) {
43             MessageOrEnumWithScope::Message(m) => m,
44             _ => panic!("not a message: {}", fqn),
45         }
46     }
47 
48     // find message or enum by fully qualified name
find_message_or_enum( &'a self, fqn: &ProtobufAbsolutePath, ) -> MessageOrEnumWithScope<'a>49     pub fn find_message_or_enum(
50         &'a self,
51         fqn: &ProtobufAbsolutePath,
52     ) -> MessageOrEnumWithScope<'a> {
53         assert!(!fqn.is_empty());
54         self.packages()
55             .into_iter()
56             .flat_map(|p| p.find_message_or_enum_abs(fqn))
57             .next()
58             .expect(&format!("enum not found by name: {}", fqn))
59     }
60 }
61 
62 #[derive(Clone, Debug)]
63 pub(crate) struct FileScope<'a> {
64     pub file_descriptor: &'a FileDescriptorProto,
65 }
66 
67 impl<'a> FileScope<'a> {
get_package(&self) -> ProtobufAbsolutePath68     fn get_package(&self) -> ProtobufAbsolutePath {
69         ProtobufRelativePath::from(self.file_descriptor.get_package()).into_absolute()
70     }
71 
syntax(&self) -> Syntax72     pub fn syntax(&self) -> Syntax {
73         Syntax::parse(self.file_descriptor.get_syntax())
74     }
75 
to_scope(&self) -> Scope<'a>76     pub fn to_scope(&self) -> Scope<'a> {
77         Scope {
78             file_scope: self.clone(),
79             path: Vec::new(),
80         }
81     }
82 
find_message_or_enum( &self, name: &ProtobufRelativePath, ) -> Option<MessageOrEnumWithScope<'a>>83     fn find_message_or_enum(
84         &self,
85         name: &ProtobufRelativePath,
86     ) -> Option<MessageOrEnumWithScope<'a>> {
87         self.find_messages_and_enums()
88             .into_iter()
89             .filter(|e| e.protobuf_name_to_package() == *name)
90             .next()
91     }
92 
find_message_or_enum_abs( &self, name: &ProtobufAbsolutePath, ) -> Option<MessageOrEnumWithScope<'a>>93     fn find_message_or_enum_abs(
94         &self,
95         name: &ProtobufAbsolutePath,
96     ) -> Option<MessageOrEnumWithScope<'a>> {
97         match name.remove_prefix(&self.get_package()) {
98             Some(ref rem) => self.find_message_or_enum(rem),
99             None => None,
100         }
101     }
102 
103     // find all enums in given file descriptor
_find_enums(&self) -> Vec<EnumWithScope<'a>>104     pub fn _find_enums(&self) -> Vec<EnumWithScope<'a>> {
105         let mut r = Vec::new();
106 
107         self.to_scope().walk_scopes(|scope| {
108             r.extend(scope.get_enums());
109         });
110 
111         r
112     }
113 
114     // find all messages in given file descriptor
_find_messages(&self) -> Vec<MessageWithScope<'a>>115     pub fn _find_messages(&self) -> Vec<MessageWithScope<'a>> {
116         let mut r = Vec::new();
117 
118         self.to_scope().walk_scopes(|scope| {
119             r.extend(scope.get_messages());
120         });
121 
122         r
123     }
124 
125     // find all messages and enums in given file descriptor
find_messages_and_enums(&self) -> Vec<MessageOrEnumWithScope<'a>>126     pub fn find_messages_and_enums(&self) -> Vec<MessageOrEnumWithScope<'a>> {
127         let mut r = Vec::new();
128 
129         self.to_scope().walk_scopes(|scope| {
130             r.extend(scope.get_messages_and_enums());
131         });
132 
133         r
134     }
135 }
136 
137 #[derive(Clone, Debug)]
138 pub(crate) struct Scope<'a> {
139     pub file_scope: FileScope<'a>,
140     pub path: Vec<&'a DescriptorProto>,
141 }
142 
143 impl<'a> Scope<'a> {
get_file_descriptor(&self) -> &'a FileDescriptorProto144     pub fn get_file_descriptor(&self) -> &'a FileDescriptorProto {
145         self.file_scope.file_descriptor
146     }
147 
148     // get message descriptors in this scope
get_message_descriptors(&self) -> &'a [DescriptorProto]149     fn get_message_descriptors(&self) -> &'a [DescriptorProto] {
150         if self.path.is_empty() {
151             &self.file_scope.file_descriptor.get_message_type()
152         } else {
153             &self.path.last().unwrap().get_nested_type()
154         }
155     }
156 
157     // get enum descriptors in this scope
get_enum_descriptors(&self) -> &'a [EnumDescriptorProto]158     fn get_enum_descriptors(&self) -> &'a [EnumDescriptorProto] {
159         if self.path.is_empty() {
160             &self.file_scope.file_descriptor.get_enum_type()
161         } else {
162             &self.path.last().unwrap().get_enum_type()
163         }
164     }
165 
166     // get messages with attached scopes in this scope
get_messages(&self) -> Vec<MessageWithScope<'a>>167     pub fn get_messages(&self) -> Vec<MessageWithScope<'a>> {
168         self.get_message_descriptors()
169             .iter()
170             .map(|m| MessageWithScope {
171                 scope: self.clone(),
172                 message: m,
173             })
174             .collect()
175     }
176 
177     // get enums with attached scopes in this scope
get_enums(&self) -> Vec<EnumWithScope<'a>>178     pub fn get_enums(&self) -> Vec<EnumWithScope<'a>> {
179         self.get_enum_descriptors()
180             .iter()
181             .map(|e| EnumWithScope {
182                 scope: self.clone(),
183                 en: e,
184             })
185             .collect()
186     }
187 
188     // get messages and enums with attached scopes in this scope
get_messages_and_enums(&self) -> Vec<MessageOrEnumWithScope<'a>>189     pub fn get_messages_and_enums(&self) -> Vec<MessageOrEnumWithScope<'a>> {
190         self.get_messages()
191             .into_iter()
192             .map(|m| MessageOrEnumWithScope::Message(m))
193             .chain(
194                 self.get_enums()
195                     .into_iter()
196                     .map(|m| MessageOrEnumWithScope::Enum(m)),
197             )
198             .collect()
199     }
200 
201     // nested scopes, i. e. scopes of nested messages
nested_scopes(&self) -> Vec<Scope<'a>>202     fn nested_scopes(&self) -> Vec<Scope<'a>> {
203         self.get_message_descriptors()
204             .iter()
205             .map(|m| {
206                 let mut nested = self.clone();
207                 nested.path.push(m);
208                 nested
209             })
210             .collect()
211     }
212 
walk_scopes_impl<F: FnMut(&Scope<'a>)>(&self, callback: &mut F)213     fn walk_scopes_impl<F: FnMut(&Scope<'a>)>(&self, callback: &mut F) {
214         (*callback)(self);
215 
216         for nested in self.nested_scopes() {
217             nested.walk_scopes_impl(callback);
218         }
219     }
220 
221     // apply callback for this scope and all nested scopes
walk_scopes<F>(&self, mut callback: F) where F: FnMut(&Scope<'a>),222     fn walk_scopes<F>(&self, mut callback: F)
223     where
224         F: FnMut(&Scope<'a>),
225     {
226         self.walk_scopes_impl(&mut callback);
227     }
228 
prefix(&self) -> String229     pub fn prefix(&self) -> String {
230         if self.path.is_empty() {
231             "".to_string()
232         } else {
233             let v: Vec<&'a str> = self.path.iter().map(|m| m.get_name()).collect();
234             let mut r = v.join(".");
235             r.push_str(".");
236             r
237         }
238     }
239 
protobuf_path_to_file(&self) -> ProtobufRelativePath240     pub fn protobuf_path_to_file(&self) -> ProtobufRelativePath {
241         ProtobufRelativePath::from_components(
242             self.path.iter().map(|m| ProtobufIdent::from(m.get_name())),
243         )
244     }
245 
protobuf_absolute_path(&self) -> ProtobufAbsolutePath246     pub fn protobuf_absolute_path(&self) -> ProtobufAbsolutePath {
247         let mut r = self.file_scope.get_package();
248         r.push_relative(&self.protobuf_path_to_file());
249         r
250     }
251 
252     // rust type name prefix for this scope
rust_prefix(&self) -> String253     pub fn rust_prefix(&self) -> String {
254         self.prefix().replace(".", "_")
255     }
256 }
257 
258 pub(crate) trait WithScope<'a> {
get_scope(&self) -> &Scope<'a>259     fn get_scope(&self) -> &Scope<'a>;
260 
get_file_descriptor(&self) -> &'a FileDescriptorProto261     fn get_file_descriptor(&self) -> &'a FileDescriptorProto {
262         self.get_scope().get_file_descriptor()
263     }
264 
265     // message or enum name
get_name(&self) -> ProtobufIdent266     fn get_name(&self) -> ProtobufIdent;
267 
escape_prefix(&self) -> &'static str268     fn escape_prefix(&self) -> &'static str;
269 
name_to_package(&self) -> String270     fn name_to_package(&self) -> String {
271         let mut r = self.get_scope().prefix();
272         r.push_str(self.get_name().get());
273         r
274     }
275 
protobuf_name_to_package(&self) -> ProtobufRelativePath276     fn protobuf_name_to_package(&self) -> ProtobufRelativePath {
277         let r = self.get_scope().protobuf_path_to_file();
278         r.append_ident(&ProtobufIdent::from(self.get_name()))
279     }
280 
281     /// Return absolute name starting with dot
name_absolute(&self) -> ProtobufAbsolutePath282     fn name_absolute(&self) -> ProtobufAbsolutePath {
283         let mut path = self.get_scope().protobuf_absolute_path();
284         path.push_simple(self.get_name());
285         path
286     }
287 
288     // rust type name of this descriptor
rust_name(&self) -> RustIdent289     fn rust_name(&self) -> RustIdent {
290         let mut r = self.get_scope().rust_prefix();
291         // Only escape if prefix is not empty
292         if r.is_empty() && rust::is_rust_keyword(self.get_name().get()) {
293             r.push_str(self.escape_prefix());
294         }
295         r.push_str(self.get_name().get());
296         RustIdent::from(r)
297     }
298 
299     // fully-qualified name of this type
rust_fq_name(&self) -> String300     fn rust_fq_name(&self) -> String {
301         format!(
302             "{}::{}",
303             proto_path_to_rust_mod(self.get_scope().get_file_descriptor().get_name()),
304             self.rust_name()
305         )
306     }
307 }
308 
309 #[derive(Clone, Debug)]
310 pub(crate) struct MessageWithScope<'a> {
311     pub scope: Scope<'a>,
312     pub message: &'a DescriptorProto,
313 }
314 
315 impl<'a> WithScope<'a> for MessageWithScope<'a> {
get_scope(&self) -> &Scope<'a>316     fn get_scope(&self) -> &Scope<'a> {
317         &self.scope
318     }
319 
escape_prefix(&self) -> &'static str320     fn escape_prefix(&self) -> &'static str {
321         "message_"
322     }
323 
get_name(&self) -> ProtobufIdent324     fn get_name(&self) -> ProtobufIdent {
325         ProtobufIdent::from(self.message.get_name())
326     }
327 }
328 
329 impl<'a> MessageWithScope<'a> {
into_scope(mut self) -> Scope<'a>330     pub fn into_scope(mut self) -> Scope<'a> {
331         self.scope.path.push(self.message);
332         self.scope
333     }
334 
to_scope(&self) -> Scope<'a>335     pub fn to_scope(&self) -> Scope<'a> {
336         self.clone().into_scope()
337     }
338 
fields(&self) -> Vec<FieldWithContext<'a>>339     pub fn fields(&self) -> Vec<FieldWithContext<'a>> {
340         self.message
341             .get_field()
342             .iter()
343             .map(|f| FieldWithContext {
344                 field: f,
345                 message: self.clone(),
346             })
347             .collect()
348     }
349 
oneofs(&self) -> Vec<OneofWithContext<'a>>350     pub fn oneofs(&self) -> Vec<OneofWithContext<'a>> {
351         self.message
352             .get_oneof_decl()
353             .iter()
354             .enumerate()
355             .map(|(index, oneof)| OneofWithContext {
356                 message: self.clone(),
357                 oneof: oneof,
358                 index: index as u32,
359             })
360             .collect()
361     }
362 
oneof_by_index(&self, index: u32) -> OneofWithContext<'a>363     pub fn oneof_by_index(&self, index: u32) -> OneofWithContext<'a> {
364         self.oneofs().swap_remove(index as usize)
365     }
366 
367     /// Pair of (key, value) if this message is map entry
map_entry(&'a self) -> Option<(FieldWithContext<'a>, FieldWithContext<'a>)>368     pub fn map_entry(&'a self) -> Option<(FieldWithContext<'a>, FieldWithContext<'a>)> {
369         if self.message.get_options().get_map_entry() {
370             let key = self
371                 .fields()
372                 .into_iter()
373                 .find(|f| f.field.get_number() == 1)
374                 .unwrap();
375             let value = self
376                 .fields()
377                 .into_iter()
378                 .find(|f| f.field.get_number() == 2)
379                 .unwrap();
380             Some((key, value))
381         } else {
382             None
383         }
384     }
385 }
386 
387 #[derive(Clone, Debug)]
388 pub(crate) struct EnumWithScope<'a> {
389     pub scope: Scope<'a>,
390     pub en: &'a EnumDescriptorProto,
391 }
392 
393 impl<'a> EnumWithScope<'a> {
values(&self) -> Vec<EnumValueWithContext<'a>>394     pub fn values(&self) -> Vec<EnumValueWithContext<'a>> {
395         self.en
396             .get_value()
397             .iter()
398             .map(|v| EnumValueWithContext {
399                 _en: self.clone(),
400                 proto: v,
401             })
402             .collect()
403     }
404 
405     // find enum value by protobuf name
value_by_name(&self, name: &str) -> EnumValueWithContext<'a>406     pub fn value_by_name(&self, name: &str) -> EnumValueWithContext<'a> {
407         self.values()
408             .into_iter()
409             .find(|v| v.proto.get_name() == name)
410             .unwrap()
411     }
412 }
413 
414 #[derive(Clone, Debug)]
415 pub(crate) struct EnumValueWithContext<'a> {
416     _en: EnumWithScope<'a>,
417     pub proto: &'a EnumValueDescriptorProto,
418 }
419 
420 impl<'a> EnumValueWithContext<'a> {
rust_name(&self) -> RustIdent421     pub fn rust_name(&self) -> RustIdent {
422         let mut r = String::new();
423         if rust::is_rust_keyword(self.proto.get_name()) {
424             r.push_str("value_");
425         }
426         r.push_str(self.proto.get_name());
427         RustIdent::new(&r)
428     }
429 }
430 
431 impl<'a> WithScope<'a> for EnumWithScope<'a> {
get_scope(&self) -> &Scope<'a>432     fn get_scope(&self) -> &Scope<'a> {
433         &self.scope
434     }
435 
escape_prefix(&self) -> &'static str436     fn escape_prefix(&self) -> &'static str {
437         "enum_"
438     }
439 
get_name(&self) -> ProtobufIdent440     fn get_name(&self) -> ProtobufIdent {
441         ProtobufIdent::from(self.en.get_name())
442     }
443 }
444 
445 pub(crate) enum MessageOrEnumWithScope<'a> {
446     Message(MessageWithScope<'a>),
447     Enum(EnumWithScope<'a>),
448 }
449 
450 impl<'a> WithScope<'a> for MessageOrEnumWithScope<'a> {
get_scope(&self) -> &Scope<'a>451     fn get_scope(&self) -> &Scope<'a> {
452         match self {
453             &MessageOrEnumWithScope::Message(ref m) => m.get_scope(),
454             &MessageOrEnumWithScope::Enum(ref e) => e.get_scope(),
455         }
456     }
457 
escape_prefix(&self) -> &'static str458     fn escape_prefix(&self) -> &'static str {
459         match self {
460             &MessageOrEnumWithScope::Message(ref m) => m.escape_prefix(),
461             &MessageOrEnumWithScope::Enum(ref e) => e.escape_prefix(),
462         }
463     }
464 
get_name(&self) -> ProtobufIdent465     fn get_name(&self) -> ProtobufIdent {
466         match self {
467             &MessageOrEnumWithScope::Message(ref m) => m.get_name(),
468             &MessageOrEnumWithScope::Enum(ref e) => e.get_name(),
469         }
470     }
471 }
472 
473 #[derive(Clone)]
474 pub(crate) struct FieldWithContext<'a> {
475     pub field: &'a FieldDescriptorProto,
476     pub message: MessageWithScope<'a>,
477 }
478 
479 impl<'a> FieldWithContext<'a> {
is_oneof(&self) -> bool480     pub fn is_oneof(&self) -> bool {
481         self.field.has_oneof_index()
482     }
483 
oneof(&self) -> Option<OneofWithContext<'a>>484     pub fn oneof(&self) -> Option<OneofWithContext<'a>> {
485         if self.is_oneof() {
486             Some(
487                 self.message
488                     .oneof_by_index(self.field.get_oneof_index() as u32),
489             )
490         } else {
491             None
492         }
493     }
494 
number(&self) -> u32495     pub fn number(&self) -> u32 {
496         self.field.get_number() as u32
497     }
498 
499     /// Shortcut
name(&self) -> &str500     pub fn name(&self) -> &str {
501         self.field.get_name()
502     }
503 
rust_name(&self) -> RustIdent504     pub fn rust_name(&self) -> RustIdent {
505         rust_field_name_for_protobuf_field_name(self.name())
506     }
507 
508     // From field to file root
_containing_messages(&self) -> Vec<&'a DescriptorProto>509     pub fn _containing_messages(&self) -> Vec<&'a DescriptorProto> {
510         let mut r = Vec::new();
511         r.push(self.message.message);
512         r.extend(self.message.scope.path.iter().rev());
513         r
514     }
515 }
516 
517 #[derive(Clone)]
518 pub(crate) struct OneofVariantWithContext<'a> {
519     pub oneof: &'a OneofWithContext<'a>,
520     pub field: &'a FieldDescriptorProto,
521 }
522 
523 #[derive(Clone)]
524 pub(crate) struct OneofWithContext<'a> {
525     pub oneof: &'a OneofDescriptorProto,
526     pub index: u32,
527     pub message: MessageWithScope<'a>,
528 }
529 
530 impl<'a> OneofWithContext<'a> {
field_name(&'a self) -> RustIdent531     pub fn field_name(&'a self) -> RustIdent {
532         return rust_field_name_for_protobuf_field_name(self.oneof.get_name());
533     }
534 
535     // rust type name of enum
rust_name(&self) -> RustIdentWithPath536     pub fn rust_name(&self) -> RustIdentWithPath {
537         RustIdentWithPath::from(format!(
538             "{}_oneof_{}",
539             self.message.rust_name(),
540             self.oneof.get_name()
541         ))
542     }
543 
variants(&'a self) -> Vec<OneofVariantWithContext<'a>>544     pub fn variants(&'a self) -> Vec<OneofVariantWithContext<'a>> {
545         self.message
546             .fields()
547             .iter()
548             .filter(|f| f.field.has_oneof_index() && f.field.get_oneof_index() == self.index as i32)
549             .map(|f| OneofVariantWithContext {
550                 oneof: self,
551                 field: &f.field,
552             })
553             .collect()
554     }
555 }
556