• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use std::ops::Deref;
2 
3 use protobuf::reflect::EnumDescriptor;
4 use protobuf::reflect::EnumValueDescriptor;
5 use protobuf::reflect::FieldDescriptor;
6 use protobuf::reflect::FileDescriptor;
7 use protobuf::reflect::MessageDescriptor;
8 use protobuf::reflect::OneofDescriptor;
9 use protobuf_parse::ProtobufAbsPath;
10 use protobuf_parse::ProtobufAbsPathRef;
11 use protobuf_parse::ProtobufIdentRef;
12 use protobuf_parse::ProtobufRelPath;
13 use protobuf_parse::ProtobufRelPathRef;
14 
15 use crate::customize::Customize;
16 use crate::gen::field::rust_field_name_for_protobuf_field_name;
17 use crate::gen::file_and_mod::FileAndMod;
18 use crate::gen::map::map_entry;
19 use crate::gen::message::message_name_to_nested_mod_name;
20 use crate::gen::paths::proto_path_to_rust_mod;
21 use crate::gen::rust::ident::RustIdent;
22 use crate::gen::rust::ident_with_path::RustIdentWithPath;
23 use crate::gen::rust::rel_path::RustRelativePath;
24 use crate::gen::strx::capitalize;
25 
26 pub(crate) struct RootScope<'a> {
27     pub file_descriptors: &'a [FileDescriptor],
28 }
29 
30 impl<'a> RootScope<'a> {
packages(&'a self) -> Vec<FileScope<'a>>31     fn packages(&'a self) -> Vec<FileScope<'a>> {
32         self.file_descriptors
33             .iter()
34             .map(|fd| FileScope {
35                 file_descriptor: fd,
36             })
37             .collect()
38     }
39 
40     // find enum by fully qualified name
_find_enum(&'a self, fqn: &ProtobufAbsPath) -> EnumWithScope<'a>41     pub fn _find_enum(&'a self, fqn: &ProtobufAbsPath) -> EnumWithScope<'a> {
42         match self.find_message_or_enum(fqn) {
43             MessageOrEnumWithScope::Enum(e) => e,
44             _ => panic!("not an enum: {}", fqn),
45         }
46     }
47 
48     // find message by fully qualified name
find_message(&'a self, fqn: &ProtobufAbsPath) -> MessageWithScope<'a>49     pub fn find_message(&'a self, fqn: &ProtobufAbsPath) -> MessageWithScope<'a> {
50         match self.find_message_or_enum(fqn) {
51             MessageOrEnumWithScope::Message(m) => m,
52             _ => panic!("not a message: {}", fqn),
53         }
54     }
55 
56     // find message or enum by fully qualified name
find_message_or_enum(&'a self, fqn: &ProtobufAbsPath) -> MessageOrEnumWithScope<'a>57     pub fn find_message_or_enum(&'a self, fqn: &ProtobufAbsPath) -> MessageOrEnumWithScope<'a> {
58         assert!(!fqn.is_root());
59         self.packages()
60             .into_iter()
61             .flat_map(|p| p.find_message_or_enum_abs(fqn))
62             .next()
63             .expect(&format!("enum not found by name: {}", fqn))
64     }
65 }
66 
67 #[derive(Clone, Debug)]
68 pub(crate) struct FileScope<'a> {
69     pub file_descriptor: &'a FileDescriptor,
70 }
71 
72 impl<'a> Deref for FileScope<'a> {
73     type Target = FileDescriptor;
74 
deref(&self) -> &Self::Target75     fn deref(&self) -> &Self::Target {
76         self.file_descriptor
77     }
78 }
79 
80 impl<'a> FileScope<'a> {
package(&self) -> ProtobufAbsPath81     fn package(&self) -> ProtobufAbsPath {
82         ProtobufAbsPath::package_from_file_descriptor(self.file_descriptor)
83     }
84 
to_scope(&self) -> Scope<'a>85     pub fn to_scope(&self) -> Scope<'a> {
86         Scope {
87             file_scope: self.clone(),
88             path: Vec::new(),
89         }
90     }
91 
find_message_or_enum( &self, name: &ProtobufRelPathRef, ) -> Option<MessageOrEnumWithScope<'a>>92     fn find_message_or_enum(
93         &self,
94         name: &ProtobufRelPathRef,
95     ) -> Option<MessageOrEnumWithScope<'a>> {
96         self.find_messages_and_enums()
97             .into_iter()
98             .filter(|e| e.protobuf_name_to_package().as_ref() == name)
99             .next()
100     }
101 
find_message_or_enum_abs( &self, name: &ProtobufAbsPathRef, ) -> Option<MessageOrEnumWithScope<'a>>102     fn find_message_or_enum_abs(
103         &self,
104         name: &ProtobufAbsPathRef,
105     ) -> Option<MessageOrEnumWithScope<'a>> {
106         let name = name.to_owned();
107         match name.remove_prefix(&self.package()) {
108             Some(rem) => self.find_message_or_enum(&rem),
109             None => None,
110         }
111     }
112 
113     // find all enums in given file descriptor
find_enums(&self) -> Vec<EnumWithScope<'a>>114     pub fn find_enums(&self) -> Vec<EnumWithScope<'a>> {
115         let mut r = Vec::new();
116 
117         self.to_scope().walk_scopes(|scope| {
118             r.extend(scope.enums());
119         });
120 
121         r
122     }
123 
124     /// Find all messages in given file descriptor
find_messages(&self) -> Vec<MessageWithScope<'a>>125     pub fn find_messages(&self) -> Vec<MessageWithScope<'a>> {
126         let mut r = Vec::new();
127 
128         self.to_scope().walk_scopes(|scope| {
129             r.extend(scope.messages());
130         });
131 
132         r
133     }
134 
135     /// Find all messages in given file descriptor, except map messages
find_messages_except_map(&self) -> Vec<MessageWithScope<'a>>136     pub fn find_messages_except_map(&self) -> Vec<MessageWithScope<'a>> {
137         self.find_messages()
138             .into_iter()
139             .filter(|m| !m.is_map())
140             .collect()
141     }
142 
143     /// find all messages and enums in given file descriptor
find_messages_and_enums(&self) -> Vec<MessageOrEnumWithScope<'a>>144     pub fn find_messages_and_enums(&self) -> Vec<MessageOrEnumWithScope<'a>> {
145         let mut r = Vec::new();
146 
147         self.to_scope().walk_scopes(|scope| {
148             r.extend(scope.messages_and_enums());
149         });
150 
151         r
152     }
153 }
154 
155 #[derive(Clone, Debug)]
156 pub(crate) struct Scope<'a> {
157     pub file_scope: FileScope<'a>,
158     pub path: Vec<MessageDescriptor>,
159 }
160 
161 impl<'a> Scope<'a> {
file_descriptor(&self) -> FileDescriptor162     pub(crate) fn file_descriptor(&self) -> FileDescriptor {
163         self.file_scope.file_descriptor.clone()
164     }
165 
166     // get message descriptors in this scope
message_descriptors(&self) -> Vec<MessageDescriptor>167     fn message_descriptors(&self) -> Vec<MessageDescriptor> {
168         if self.path.is_empty() {
169             self.file_scope.file_descriptor.messages().collect()
170         } else {
171             self.path.last().unwrap().nested_messages().collect()
172         }
173     }
174 
175     // get enum descriptors in this scope
enum_descriptors(&self) -> Vec<EnumDescriptor>176     fn enum_descriptors(&self) -> Vec<EnumDescriptor> {
177         if self.path.is_empty() {
178             self.file_scope.file_descriptor.enums().collect()
179         } else {
180             self.path.last().unwrap().nested_enums().collect()
181         }
182     }
183 
184     // get messages with attached scopes in this scope
messages(&self) -> Vec<MessageWithScope<'a>>185     pub fn messages(&self) -> Vec<MessageWithScope<'a>> {
186         self.message_descriptors()
187             .into_iter()
188             .map(|message| MessageWithScope {
189                 scope: self.clone(),
190                 message,
191             })
192             .collect()
193     }
194 
195     // get enums with attached scopes in this scope
enums(&self) -> Vec<EnumWithScope<'a>>196     pub fn enums(&self) -> Vec<EnumWithScope<'a>> {
197         self.enum_descriptors()
198             .into_iter()
199             .map(|en| EnumWithScope {
200                 scope: self.clone(),
201                 en,
202             })
203             .collect()
204     }
205 
206     // get messages and enums with attached scopes in this scope
messages_and_enums(&self) -> Vec<MessageOrEnumWithScope<'a>>207     pub fn messages_and_enums(&self) -> Vec<MessageOrEnumWithScope<'a>> {
208         self.messages()
209             .into_iter()
210             .map(|m| MessageOrEnumWithScope::Message(m))
211             .chain(
212                 self.enums()
213                     .into_iter()
214                     .map(|m| MessageOrEnumWithScope::Enum(m)),
215             )
216             .collect()
217     }
218 
219     // nested scopes, i. e. scopes of nested messages
nested_scopes(&self) -> Vec<Scope<'a>>220     fn nested_scopes(&self) -> Vec<Scope<'a>> {
221         self.message_descriptors()
222             .into_iter()
223             .map(|m| {
224                 let mut nested = self.clone();
225                 nested.path.push(m);
226                 nested
227             })
228             .collect()
229     }
230 
walk_scopes_impl<F: FnMut(&Scope<'a>)>(&self, callback: &mut F)231     fn walk_scopes_impl<F: FnMut(&Scope<'a>)>(&self, callback: &mut F) {
232         (*callback)(self);
233 
234         for nested in self.nested_scopes() {
235             nested.walk_scopes_impl(callback);
236         }
237     }
238 
239     // apply callback for this scope and all nested scopes
walk_scopes<F>(&self, mut callback: F) where F: FnMut(&Scope<'a>),240     fn walk_scopes<F>(&self, mut callback: F)
241     where
242         F: FnMut(&Scope<'a>),
243     {
244         self.walk_scopes_impl(&mut callback);
245     }
246 
rust_path_to_file(&self) -> RustRelativePath247     pub fn rust_path_to_file(&self) -> RustRelativePath {
248         RustRelativePath::from_idents(
249             self.path
250                 .iter()
251                 .map(|m| message_name_to_nested_mod_name(m.name())),
252         )
253     }
254 
path_str(&self) -> String255     pub fn path_str(&self) -> String {
256         let v: Vec<&str> = self.path.iter().map(|m| m.name()).collect();
257         v.join(".")
258     }
259 
prefix(&self) -> String260     pub fn prefix(&self) -> String {
261         let path_str = self.path_str();
262         if path_str.is_empty() {
263             path_str
264         } else {
265             format!("{}.", path_str)
266         }
267     }
268 
protobuf_path_to_file(&self) -> ProtobufRelPath269     pub fn protobuf_path_to_file(&self) -> ProtobufRelPath {
270         ProtobufRelPath::from_components(self.path.iter().map(|m| ProtobufIdentRef::new(m.name())))
271     }
272 
protobuf_absolute_path(&self) -> ProtobufAbsPath273     pub fn protobuf_absolute_path(&self) -> ProtobufAbsPath {
274         let mut r = self.file_scope.package();
275         r.push_relative(&self.protobuf_path_to_file());
276         r
277     }
278 
file_and_mod(&self, customize: Customize) -> FileAndMod279     pub fn file_and_mod(&self, customize: Customize) -> FileAndMod {
280         FileAndMod {
281             file: self.file_scope.file_descriptor.proto().name().to_owned(),
282             relative_mod: self.rust_path_to_file(),
283             customize,
284         }
285     }
286 }
287 
288 pub(crate) trait WithScope<'a> {
scope(&self) -> &Scope<'a>289     fn scope(&self) -> &Scope<'a>;
290 
file_descriptor(&self) -> FileDescriptor291     fn file_descriptor(&self) -> FileDescriptor {
292         self.scope().file_descriptor()
293     }
294 
295     // message or enum name
name(&self) -> &ProtobufIdentRef296     fn name(&self) -> &ProtobufIdentRef;
297 
name_to_package(&self) -> String298     fn name_to_package(&self) -> String {
299         let mut r = self.scope().prefix();
300         r.push_str(&self.name());
301         r
302     }
303 
protobuf_name_to_package(&self) -> ProtobufRelPath304     fn protobuf_name_to_package(&self) -> ProtobufRelPath {
305         let r = self.scope().protobuf_path_to_file();
306         r.append_ident(ProtobufIdentRef::new(self.name()))
307     }
308 
309     /// Return absolute name starting with dot
name_absolute(&self) -> ProtobufAbsPath310     fn name_absolute(&self) -> ProtobufAbsPath {
311         let mut path = self.scope().protobuf_absolute_path();
312         path.push_simple(self.name());
313         path
314     }
315 
316     // rust type name of this descriptor
rust_name(&self) -> RustIdent317     fn rust_name(&self) -> RustIdent {
318         let rust_name = capitalize(&self.name());
319         RustIdent::new(&rust_name)
320     }
321 
rust_name_to_file(&self) -> RustIdentWithPath322     fn rust_name_to_file(&self) -> RustIdentWithPath {
323         self.scope()
324             .rust_path_to_file()
325             .into_path()
326             .with_ident(self.rust_name())
327     }
328 
329     // fully-qualified name of this type
rust_name_with_file(&self) -> RustIdentWithPath330     fn rust_name_with_file(&self) -> RustIdentWithPath {
331         let mut r = self.rust_name_to_file();
332         r.prepend_ident(proto_path_to_rust_mod(
333             self.scope().file_descriptor().name(),
334         ));
335         r
336     }
337 }
338 
339 #[derive(Clone, Debug)]
340 pub(crate) struct MessageWithScope<'a> {
341     pub scope: Scope<'a>,
342     pub message: MessageDescriptor,
343 }
344 
345 impl<'a> WithScope<'a> for MessageWithScope<'a> {
scope(&self) -> &Scope<'a>346     fn scope(&self) -> &Scope<'a> {
347         &self.scope
348     }
349 
name(&self) -> &ProtobufIdentRef350     fn name(&self) -> &ProtobufIdentRef {
351         ProtobufIdentRef::new(self.message.name())
352     }
353 }
354 
355 impl<'a> MessageWithScope<'a> {
into_scope(mut self) -> Scope<'a>356     pub fn into_scope(mut self) -> Scope<'a> {
357         self.scope.path.push(self.message);
358         self.scope
359     }
360 
to_scope(&self) -> Scope<'a>361     pub fn to_scope(&self) -> Scope<'a> {
362         self.clone().into_scope()
363     }
364 
fields(&self) -> Vec<FieldWithContext<'a>>365     pub fn fields(&self) -> Vec<FieldWithContext<'a>> {
366         self.message
367             .fields()
368             .into_iter()
369             .map(|field| FieldWithContext {
370                 field,
371                 message: self.clone(),
372             })
373             .collect()
374     }
375 
oneofs(&self) -> Vec<OneofWithContext<'a>>376     pub fn oneofs(&self) -> Vec<OneofWithContext<'a>> {
377         self.message
378             .oneofs()
379             .into_iter()
380             .map(|oneof| OneofWithContext {
381                 message: self.clone(),
382                 oneof,
383             })
384             .collect()
385     }
386 
mod_name(&self) -> RustIdent387     pub fn mod_name(&self) -> RustIdent {
388         message_name_to_nested_mod_name(self.message.name())
389     }
390 
391     /// This message is a special message which is a map.
is_map(&self) -> bool392     pub fn is_map(&self) -> bool {
393         map_entry(self).is_some()
394     }
395 }
396 
397 #[derive(Clone, Debug)]
398 pub(crate) struct EnumWithScope<'a> {
399     pub scope: Scope<'a>,
400     pub en: EnumDescriptor,
401 }
402 
403 impl<'a> EnumWithScope<'a> {
values(&self) -> Vec<EnumValueWithContext<'a>>404     pub fn values(&self) -> Vec<EnumValueWithContext<'a>> {
405         self.en
406             .values()
407             .into_iter()
408             .map(|v| EnumValueWithContext {
409                 en: self.clone(),
410                 proto: v,
411             })
412             .collect()
413     }
414 
415     // find enum value by protobuf name
value_by_name(&self, name: &str) -> EnumValueWithContext<'a>416     pub fn value_by_name(&self, name: &str) -> EnumValueWithContext<'a> {
417         self.values()
418             .into_iter()
419             .find(|v| v.proto.proto().name() == name)
420             .unwrap()
421     }
422 }
423 
424 #[derive(Clone, Debug)]
425 pub(crate) struct EnumValueWithContext<'a> {
426     pub en: EnumWithScope<'a>,
427     pub proto: EnumValueDescriptor,
428 }
429 
430 impl<'a> EnumValueWithContext<'a> {
rust_name(&self) -> RustIdent431     pub fn rust_name(&self) -> RustIdent {
432         // TODO: camel case or something.
433         RustIdent::new(self.proto.name())
434     }
435 }
436 
437 impl<'a> WithScope<'a> for EnumWithScope<'a> {
scope(&self) -> &Scope<'a>438     fn scope(&self) -> &Scope<'a> {
439         &self.scope
440     }
441 
name(&self) -> &ProtobufIdentRef442     fn name(&self) -> &ProtobufIdentRef {
443         ProtobufIdentRef::new(self.en.name())
444     }
445 }
446 
447 pub(crate) enum MessageOrEnumWithScope<'a> {
448     Message(MessageWithScope<'a>),
449     Enum(EnumWithScope<'a>),
450 }
451 
452 impl<'a> WithScope<'a> for MessageOrEnumWithScope<'a> {
scope(&self) -> &Scope<'a>453     fn scope(&self) -> &Scope<'a> {
454         match self {
455             MessageOrEnumWithScope::Message(m) => m.scope(),
456             MessageOrEnumWithScope::Enum(e) => e.scope(),
457         }
458     }
459 
name(&self) -> &ProtobufIdentRef460     fn name(&self) -> &ProtobufIdentRef {
461         match self {
462             MessageOrEnumWithScope::Message(m) => m.name(),
463             MessageOrEnumWithScope::Enum(e) => e.name(),
464         }
465     }
466 }
467 
468 #[derive(Clone)]
469 pub(crate) struct FieldWithContext<'a> {
470     pub field: FieldDescriptor,
471     pub message: MessageWithScope<'a>,
472 }
473 
474 impl<'a> Deref for FieldWithContext<'a> {
475     type Target = FieldDescriptor;
476 
deref(&self) -> &Self::Target477     fn deref(&self) -> &Self::Target {
478         &self.field
479     }
480 }
481 
482 impl<'a> FieldWithContext<'a> {
is_oneof(&self) -> bool483     pub fn is_oneof(&self) -> bool {
484         self.field.containing_oneof().is_some()
485     }
486 
oneof(&self) -> Option<OneofWithContext<'a>>487     pub fn oneof(&self) -> Option<OneofWithContext<'a>> {
488         match self.field.containing_oneof() {
489             Some(oneof) => Some(OneofWithContext {
490                 message: self.message.clone(),
491                 oneof,
492             }),
493             None => None,
494         }
495     }
496 }
497 
498 #[derive(Clone)]
499 pub(crate) struct OneofVariantWithContext<'a> {
500     pub oneof: &'a OneofWithContext<'a>,
501     pub field: FieldDescriptor,
502 }
503 
504 #[derive(Clone)]
505 pub(crate) struct OneofWithContext<'a> {
506     pub oneof: OneofDescriptor,
507     pub message: MessageWithScope<'a>,
508 }
509 
510 impl<'a> OneofWithContext<'a> {
field_name(&'a self) -> RustIdent511     pub fn field_name(&'a self) -> RustIdent {
512         return rust_field_name_for_protobuf_field_name(self.oneof.name());
513     }
514 
515     // rust type name of enum
rust_name(&self) -> RustIdentWithPath516     pub fn rust_name(&self) -> RustIdentWithPath {
517         let type_name = RustIdent::from(capitalize(self.oneof.name()));
518         self.message
519             .to_scope()
520             .rust_path_to_file()
521             .into_path()
522             .with_ident(type_name)
523     }
524 
variants(&'a self) -> Vec<OneofVariantWithContext<'a>>525     pub fn variants(&'a self) -> Vec<OneofVariantWithContext<'a>> {
526         self.message
527             .fields()
528             .into_iter()
529             .filter(|f| f.field.containing_oneof().as_ref() == Some(&self.oneof))
530             .map(|f| OneofVariantWithContext {
531                 oneof: self,
532                 field: f.field,
533             })
534             .collect()
535     }
536 }
537