1 use protobuf::descriptor::FileDescriptorProto;
2 use protobuf::descriptor::DescriptorProto;
3 use protobuf::descriptor::EnumDescriptorProto;
4 use protobuf::descriptor::EnumValueDescriptorProto;
5 use protobuf::descriptor::FieldDescriptorProto;
6 use protobuf::descriptor::OneofDescriptorProto;
7 use rust_name::RustIdent;
8 use rust_name::RustRelativePath;
9 use rust_name::RustIdentWithPath;
10 use strx::capitalize;
11 use rust::is_rust_keyword;
12 use file::proto_path_to_rust_mod;
13 use syntax::Syntax;
14 use ::{rust, Customize};
15 use message::message_name_to_nested_mod_name;
16 use protobuf_name::ProtobufAbsolutePath;
17 use protobuf_name::ProtobufRelativePath;
18 use protobuf_name::ProtobufIdent;
19 use field::rust_field_name_for_protobuf_field_name;
20 use file_and_mod::FileAndMod;
21 
22 
23 pub(crate) struct RootScope<'a> {
24     pub file_descriptors: &'a [FileDescriptorProto],
25 }
26 
27 impl<'a> RootScope<'a> {
packages(&'a self) -> Vec<FileScope<'a>>28     fn packages(&'a self) -> Vec<FileScope<'a>> {
29         self.file_descriptors
30             .iter()
31             .map(|fd| FileScope {
32                 file_descriptor: fd,
33             }).collect()
34     }
35 
36     // find enum by fully qualified name
_find_enum(&'a self, fqn: &ProtobufAbsolutePath) -> EnumWithScope<'a>37     pub fn _find_enum(&'a self, fqn: &ProtobufAbsolutePath) -> EnumWithScope<'a> {
38         match self.find_message_or_enum(fqn) {
39             MessageOrEnumWithScope::Enum(e) => e,
40             _ => panic!("not an enum: {}", fqn),
41         }
42     }
43 
44     // find message by fully qualified name
find_message(&'a self, fqn: &ProtobufAbsolutePath) -> MessageWithScope<'a>45     pub fn find_message(&'a self, fqn: &ProtobufAbsolutePath) -> MessageWithScope<'a> {
46         match self.find_message_or_enum(fqn) {
47             MessageOrEnumWithScope::Message(m) => m,
48             _ => panic!("not a message: {}", fqn),
49         }
50     }
51 
52     // find message or enum by fully qualified name
find_message_or_enum(&'a self, fqn: &ProtobufAbsolutePath) -> MessageOrEnumWithScope<'a>53     pub fn find_message_or_enum(&'a self, fqn: &ProtobufAbsolutePath) -> MessageOrEnumWithScope<'a> {
54         assert!(!fqn.is_empty());
55         self.packages()
56             .into_iter()
57             .flat_map(|p| {
58                 p.find_message_or_enum_abs(fqn)
59             }).next()
60             .expect(&format!("enum not found by name: {}", fqn))
61     }
62 }
63 
64 #[derive(Clone, Debug)]
65 pub(crate) struct FileScope<'a> {
66     pub file_descriptor: &'a FileDescriptorProto,
67 }
68 
69 impl<'a> FileScope<'a> {
get_package(&self) -> ProtobufAbsolutePath70     fn get_package(&self) -> ProtobufAbsolutePath {
71         ProtobufRelativePath::from(self.file_descriptor.get_package()).into_absolute()
72     }
73 
syntax(&self) -> Syntax74     pub fn syntax(&self) -> Syntax {
75         Syntax::parse(self.file_descriptor.get_syntax())
76     }
77 
to_scope(&self) -> Scope<'a>78     pub fn to_scope(&self) -> Scope<'a> {
79         Scope {
80             file_scope: self.clone(),
81             path: Vec::new(),
82         }
83     }
84 
find_message_or_enum(&self, name: &ProtobufRelativePath) -> Option<MessageOrEnumWithScope<'a>>85     fn find_message_or_enum(&self, name: &ProtobufRelativePath) -> 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(&self, name: &ProtobufAbsolutePath) -> Option<MessageOrEnumWithScope<'a>> {
93         match name.remove_prefix(&self.get_package()) {
94             Some(ref rem) => self.find_message_or_enum(rem),
95             None => None,
96         }
97     }
98 
99     // find all enums in given file descriptor
_find_enums(&self) -> Vec<EnumWithScope<'a>>100     pub fn _find_enums(&self) -> Vec<EnumWithScope<'a>> {
101         let mut r = Vec::new();
102 
103         self.to_scope().walk_scopes(|scope| {
104             r.extend(scope.get_enums());
105         });
106 
107         r
108     }
109 
110     // find all messages in given file descriptor
_find_messages(&self) -> Vec<MessageWithScope<'a>>111     pub fn _find_messages(&self) -> Vec<MessageWithScope<'a>> {
112         let mut r = Vec::new();
113 
114         self.to_scope().walk_scopes(|scope| {
115             r.extend(scope.get_messages());
116         });
117 
118         r
119     }
120 
121     // find all messages and enums in given file descriptor
find_messages_and_enums(&self) -> Vec<MessageOrEnumWithScope<'a>>122     pub fn find_messages_and_enums(&self) -> Vec<MessageOrEnumWithScope<'a>> {
123         let mut r = Vec::new();
124 
125         self.to_scope().walk_scopes(|scope| {
126             r.extend(scope.get_messages_and_enums());
127         });
128 
129         r
130     }
131 }
132 
133 #[derive(Clone, Debug)]
134 pub(crate) struct Scope<'a> {
135     pub file_scope: FileScope<'a>,
136     pub path: Vec<&'a DescriptorProto>,
137 }
138 
139 impl<'a> Scope<'a> {
get_file_descriptor(&self) -> &'a FileDescriptorProto140     pub fn get_file_descriptor(&self) -> &'a FileDescriptorProto {
141         self.file_scope.file_descriptor
142     }
143 
144     // get message descriptors in this scope
get_message_descriptors(&self) -> &'a [DescriptorProto]145     fn get_message_descriptors(&self) -> &'a [DescriptorProto] {
146         if self.path.is_empty() {
147             &self.file_scope.file_descriptor.message_type
148         } else {
149             &self.path.last().unwrap().nested_type
150         }
151     }
152 
153     // get enum descriptors in this scope
get_enum_descriptors(&self) -> &'a [EnumDescriptorProto]154     fn get_enum_descriptors(&self) -> &'a [EnumDescriptorProto] {
155         if self.path.is_empty() {
156             &self.file_scope.file_descriptor.enum_type
157         } else {
158             &self.path.last().unwrap().enum_type
159         }
160     }
161 
162     // get messages with attached scopes in this scope
get_messages(&self) -> Vec<MessageWithScope<'a>>163     pub fn get_messages(&self) -> Vec<MessageWithScope<'a>> {
164         self.get_message_descriptors()
165             .iter()
166             .map(|m| MessageWithScope {
167                 scope: self.clone(),
168                 message: m,
169             }).collect()
170     }
171 
172     // get enums with attached scopes in this scope
get_enums(&self) -> Vec<EnumWithScope<'a>>173     pub fn get_enums(&self) -> Vec<EnumWithScope<'a>> {
174         self.get_enum_descriptors()
175             .iter()
176             .map(|e| EnumWithScope {
177                 scope: self.clone(),
178                 en: e,
179             }).collect()
180     }
181 
182     // get messages and enums with attached scopes in this scope
get_messages_and_enums(&self) -> Vec<MessageOrEnumWithScope<'a>>183     pub fn get_messages_and_enums(&self) -> Vec<MessageOrEnumWithScope<'a>> {
184         self.get_messages()
185             .into_iter()
186             .map(|m| MessageOrEnumWithScope::Message(m))
187             .chain(
188                 self.get_enums()
189                     .into_iter()
190                     .map(|m| MessageOrEnumWithScope::Enum(m)),
191             ).collect()
192     }
193 
194     // nested scopes, i. e. scopes of nested messages
nested_scopes(&self) -> Vec<Scope<'a>>195     fn nested_scopes(&self) -> Vec<Scope<'a>> {
196         self.get_message_descriptors()
197             .iter()
198             .map(|m| {
199                 let mut nested = self.clone();
200                 nested.path.push(m);
201                 nested
202             }).collect()
203     }
204 
walk_scopes_impl<F: FnMut(&Scope<'a>)>(&self, callback: &mut F)205     fn walk_scopes_impl<F: FnMut(&Scope<'a>)>(&self, callback: &mut F) {
206         (*callback)(self);
207 
208         for nested in self.nested_scopes() {
209             nested.walk_scopes_impl(callback);
210         }
211     }
212 
213     // apply callback for this scope and all nested scopes
walk_scopes<F>(&self, mut callback: F) where F: FnMut(&Scope<'a>),214     fn walk_scopes<F>(&self, mut callback: F)
215         where
216             F: FnMut(&Scope<'a>),
217     {
218         self.walk_scopes_impl(&mut callback);
219     }
220 
rust_path_to_file(&self) -> RustRelativePath221     pub fn rust_path_to_file(&self) -> RustRelativePath {
222         RustRelativePath::from_components(
223             self.path.iter().map(|m| message_name_to_nested_mod_name(m.get_name())))
224     }
225 
path_str(&self) -> String226     pub fn path_str(&self) -> String {
227         let v: Vec<&str> = self.path.iter().map(|m| m.get_name()).collect();
228         v.join(".")
229     }
230 
prefix(&self) -> String231     pub fn prefix(&self) -> String {
232         let path_str = self.path_str();
233         if path_str.is_empty() {
234             path_str
235         } else {
236             format!("{}.", path_str)
237         }
238     }
239 
protobuf_path_to_file(&self) -> ProtobufRelativePath240     pub fn protobuf_path_to_file(&self) -> ProtobufRelativePath {
241         ProtobufRelativePath::from_components(self.path.iter().map(|m| ProtobufIdent::from(m.get_name())))
242     }
243 
protobuf_absolute_path(&self) -> ProtobufAbsolutePath244     pub fn protobuf_absolute_path(&self) -> ProtobufAbsolutePath {
245         let mut r = self.file_scope.get_package();
246         r.push_relative(&self.protobuf_path_to_file());
247         r
248     }
249 
get_file_and_mod(&self, customize: Customize) -> FileAndMod250     pub fn get_file_and_mod(&self, customize: Customize) -> FileAndMod {
251         FileAndMod {
252             file: self.file_scope.file_descriptor.get_name().to_owned(),
253             relative_mod: self.rust_path_to_file(),
254             customize,
255         }
256     }
257 }
258 
259 pub(crate) trait WithScope<'a> {
get_scope(&self) -> &Scope<'a>260     fn get_scope(&self) -> &Scope<'a>;
261 
get_file_descriptor(&self) -> &'a FileDescriptorProto262     fn get_file_descriptor(&self) -> &'a FileDescriptorProto {
263         self.get_scope().get_file_descriptor()
264     }
265 
266     // message or enum name
get_name(&self) -> ProtobufIdent267     fn get_name(&self) -> ProtobufIdent;
268 
escape_prefix(&self) -> &'static str269     fn escape_prefix(&self) -> &'static str;
270 
name_to_package(&self) -> String271     fn name_to_package(&self) -> String {
272         let mut r = self.get_scope().prefix();
273         r.push_str(self.get_name().get());
274         r
275     }
276 
protobuf_name_to_package(&self) -> ProtobufRelativePath277     fn protobuf_name_to_package(&self) -> ProtobufRelativePath {
278         let r = self.get_scope().protobuf_path_to_file();
279         r.append_ident(&ProtobufIdent::from(self.get_name()))
280     }
281 
282     /// Return absolute name starting with dot
name_absolute(&self) -> ProtobufAbsolutePath283     fn name_absolute(&self) -> ProtobufAbsolutePath {
284         let mut path = self.get_scope().protobuf_absolute_path();
285         path.push_simple(self.get_name());
286         path
287     }
288 
289     // rust type name of this descriptor
rust_name(&self) -> RustIdent290     fn rust_name(&self) -> RustIdent {
291         let mut rust_name = capitalize(self.get_name().get());
292 
293         if is_rust_keyword(&rust_name) {
294             rust_name.insert_str(0, self.escape_prefix());
295         }
296 
297         RustIdent::new(&rust_name)
298     }
299 
rust_name_to_file(&self) -> RustIdentWithPath300     fn rust_name_to_file(&self) -> RustIdentWithPath {
301         self.get_scope().rust_path_to_file().into_path().with_ident(self.rust_name())
302     }
303 
304     // fully-qualified name of this type
rust_name_with_file(&self) -> RustIdentWithPath305     fn rust_name_with_file(&self) -> RustIdentWithPath {
306         let mut r = self.rust_name_to_file();
307         r.prepend_ident(proto_path_to_rust_mod(self.get_scope().get_file_descriptor().get_name()));
308         r
309     }
310 }
311 
312 #[derive(Clone, Debug)]
313 pub(crate) struct MessageWithScope<'a> {
314     pub scope: Scope<'a>,
315     pub message: &'a DescriptorProto,
316 }
317 
318 impl<'a> WithScope<'a> for MessageWithScope<'a> {
get_scope(&self) -> &Scope<'a>319     fn get_scope(&self) -> &Scope<'a> {
320         &self.scope
321     }
322 
escape_prefix(&self) -> &'static str323     fn escape_prefix(&self) -> &'static str {
324         "message_"
325     }
326 
get_name(&self) -> ProtobufIdent327     fn get_name(&self) -> ProtobufIdent {
328         ProtobufIdent::from(self.message.get_name())
329     }
330 }
331 
332 impl<'a> MessageWithScope<'a> {
into_scope(mut self) -> Scope<'a>333     pub fn into_scope(mut self) -> Scope<'a> {
334         self.scope.path.push(self.message);
335         self.scope
336     }
337 
to_scope(&self) -> Scope<'a>338     pub fn to_scope(&self) -> Scope<'a> {
339         self.clone().into_scope()
340     }
341 
fields(&self) -> Vec<FieldWithContext<'a>>342     pub fn fields(&self) -> Vec<FieldWithContext<'a>> {
343         self.message
344             .field
345             .iter()
346             .map(|f| FieldWithContext {
347                 field: f,
348                 message: self.clone(),
349             }).collect()
350     }
351 
oneofs(&self) -> Vec<OneofWithContext<'a>>352     pub fn oneofs(&self) -> Vec<OneofWithContext<'a>> {
353         self.message
354             .oneof_decl
355             .iter()
356             .enumerate()
357             .map(|(index, oneof)| OneofWithContext {
358                 message: self.clone(),
359                 oneof: oneof,
360                 index: index as u32,
361             }).collect()
362     }
363 
oneof_by_index(&self, index: u32) -> OneofWithContext<'a>364     pub fn oneof_by_index(&self, index: u32) -> OneofWithContext<'a> {
365         self.oneofs().swap_remove(index as usize)
366     }
367 
mod_name(&self) -> RustIdent368     pub fn mod_name(&self) -> RustIdent {
369         message_name_to_nested_mod_name(self.message.get_name())
370     }
371 }
372 
373 #[derive(Clone, Debug)]
374 pub(crate) struct EnumWithScope<'a> {
375     pub scope: Scope<'a>,
376     pub en: &'a EnumDescriptorProto,
377 }
378 
379 impl<'a> EnumWithScope<'a> {
values(&self) -> Vec<EnumValueWithContext<'a>>380     pub fn values(&self) -> Vec<EnumValueWithContext<'a>> {
381         self.en.value.iter()
382             .map(|v| {
383                 EnumValueWithContext {
384                     en: self.clone(),
385                     proto: v,
386                 }
387             })
388             .collect()
389     }
390 
391     // find enum value by protobuf name
value_by_name(&self, name: &str) -> EnumValueWithContext<'a>392     pub fn value_by_name(&self, name: &str) -> EnumValueWithContext<'a> {
393         self.values().into_iter().find(|v| v.proto.get_name() == name).unwrap()
394     }
395 }
396 
397 #[derive(Clone, Debug)]
398 pub(crate) struct EnumValueWithContext<'a> {
399     pub en: EnumWithScope<'a>,
400     pub proto: &'a EnumValueDescriptorProto,
401 }
402 
403 impl<'a> EnumValueWithContext<'a> {
rust_name(&self) -> RustIdent404     pub fn rust_name(&self) -> RustIdent {
405         let mut r = String::new();
406         if rust::is_rust_keyword(self.proto.get_name()) {
407             r.push_str("value_");
408         }
409         r.push_str(self.proto.get_name());
410         RustIdent::new(&r)
411     }
412 }
413 
414 impl<'a> WithScope<'a> for EnumWithScope<'a> {
get_scope(&self) -> &Scope<'a>415     fn get_scope(&self) -> &Scope<'a> {
416         &self.scope
417     }
418 
get_name(&self) -> ProtobufIdent419     fn get_name(&self) -> ProtobufIdent {
420         ProtobufIdent::from(self.en.get_name())
421     }
422 
escape_prefix(&self) -> &'static str423     fn escape_prefix(&self) -> &'static str {
424         "enum_"
425     }
426 }
427 
428 pub(crate) enum MessageOrEnumWithScope<'a> {
429     Message(MessageWithScope<'a>),
430     Enum(EnumWithScope<'a>),
431 }
432 
433 impl<'a> WithScope<'a> for MessageOrEnumWithScope<'a> {
get_scope(&self) -> &Scope<'a>434     fn get_scope(&self) -> &Scope<'a> {
435         match self {
436             &MessageOrEnumWithScope::Message(ref m) => m.get_scope(),
437             &MessageOrEnumWithScope::Enum(ref e) => e.get_scope(),
438         }
439     }
440 
escape_prefix(&self) -> &'static str441     fn escape_prefix(&self) -> &'static str {
442         match self {
443             &MessageOrEnumWithScope::Message(ref m) => m.escape_prefix(),
444             &MessageOrEnumWithScope::Enum(ref e) => e.escape_prefix(),
445         }
446     }
447 
get_name(&self) -> ProtobufIdent448     fn get_name(&self) -> ProtobufIdent {
449         match self {
450             &MessageOrEnumWithScope::Message(ref m) => m.get_name(),
451             &MessageOrEnumWithScope::Enum(ref e) => e.get_name(),
452         }
453     }
454 }
455 
456 #[derive(Clone)]
457 pub(crate) struct FieldWithContext<'a> {
458     pub field: &'a FieldDescriptorProto,
459     pub message: MessageWithScope<'a>,
460 }
461 
462 impl<'a> FieldWithContext<'a> {
is_oneof(&self) -> bool463     pub fn is_oneof(&self) -> bool {
464         self.field.has_oneof_index()
465     }
466 
oneof(&self) -> Option<OneofWithContext<'a>>467     pub fn oneof(&self) -> Option<OneofWithContext<'a>> {
468         if self.is_oneof() {
469             Some(
470                 self.message
471                     .oneof_by_index(self.field.get_oneof_index() as u32),
472             )
473         } else {
474             None
475         }
476     }
477 
number(&self) -> u32478     pub fn number(&self) -> u32 {
479         self.field.get_number() as u32
480     }
481 
rust_name(&self) -> RustIdent482     pub fn rust_name(&self) -> RustIdent {
483         rust_field_name_for_protobuf_field_name(self.name())
484     }
485 
486     /// Shortcut
name(&self) -> &str487     pub fn name(&self) -> &str {
488         self.field.get_name()
489     }
490 
491     // From field to file root
_containing_messages(&self) -> Vec<&'a DescriptorProto>492     pub fn _containing_messages(&self) -> Vec<&'a DescriptorProto> {
493         let mut r = Vec::new();
494         r.push(self.message.message);
495         r.extend(self.message.scope.path.iter().rev());
496         r
497     }
498 }
499 
500 #[derive(Clone)]
501 pub(crate) struct OneofVariantWithContext<'a> {
502     pub oneof: &'a OneofWithContext<'a>,
503     pub field: &'a FieldDescriptorProto,
504 }
505 
506 #[derive(Clone)]
507 pub(crate) struct OneofWithContext<'a> {
508     pub oneof: &'a OneofDescriptorProto,
509     pub index: u32,
510     pub message: MessageWithScope<'a>,
511 }
512 
513 impl<'a> OneofWithContext<'a> {
field_name(&'a self) -> RustIdent514     pub fn field_name(&'a self) -> RustIdent {
515         return rust_field_name_for_protobuf_field_name(self.oneof.get_name())
516     }
517 
518     // rust type name of enum
rust_name(&self) -> RustIdentWithPath519     pub fn rust_name(&self) -> RustIdentWithPath {
520         // TODO: escape name
521         let type_name = RustIdent::from(capitalize(self.oneof.get_name()));
522         self.message.to_scope().rust_path_to_file()
523             .into_path()
524             .with_ident(type_name)
525     }
526 
variants(&'a self) -> Vec<OneofVariantWithContext<'a>>527     pub fn variants(&'a self) -> Vec<OneofVariantWithContext<'a>> {
528         self.message
529             .fields()
530             .iter()
531             .filter(|f| f.field.has_oneof_index() && f.field.get_oneof_index() == self.index as i32)
532             .map(|f| OneofVariantWithContext {
533                 oneof: self,
534                 field: &f.field,
535             }).collect()
536     }
537 }
538 
539