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