1 // Should not be a part of public API
2 #![doc(hidden)]
3
4 use crate::descriptor::DescriptorProto;
5 use crate::descriptor::EnumDescriptorProto;
6 use crate::descriptor::EnumValueDescriptorProto;
7 use crate::descriptor::FieldDescriptorProto;
8 /// utilities to work with descriptor
9 use crate::descriptor::FileDescriptorProto;
10 use crate::descriptor::OneofDescriptorProto;
11 use crate::rust;
12 use crate::strx;
13
14 // Copy-pasted from libsyntax.
ident_start(c: char) -> bool15 fn ident_start(c: char) -> bool {
16 (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_'
17 }
18
19 // Copy-pasted from libsyntax.
ident_continue(c: char) -> bool20 fn ident_continue(c: char) -> bool {
21 (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_'
22 }
23
proto_path_to_rust_mod(path: &str) -> String24 pub fn proto_path_to_rust_mod(path: &str) -> String {
25 let without_dir = strx::remove_to(path, '/');
26 let without_suffix = strx::remove_suffix(without_dir, ".proto");
27
28 let name = without_suffix
29 .chars()
30 .enumerate()
31 .map(|(i, c)| {
32 let valid = if i == 0 {
33 ident_start(c)
34 } else {
35 ident_continue(c)
36 };
37 if valid {
38 c
39 } else {
40 '_'
41 }
42 })
43 .collect::<String>();
44
45 let name = if rust::is_rust_keyword(&name) {
46 format!("{}_pb", name)
47 } else {
48 name
49 };
50 name
51 }
52
53 pub struct RootScope<'a> {
54 pub file_descriptors: &'a [FileDescriptorProto],
55 }
56
57 impl<'a> RootScope<'a> {
packages(&'a self) -> Vec<FileScope<'a>>58 fn packages(&'a self) -> Vec<FileScope<'a>> {
59 self.file_descriptors
60 .iter()
61 .map(|fd| FileScope {
62 file_descriptor: fd,
63 })
64 .collect()
65 }
66
67 // find enum by fully qualified name
find_enum(&'a self, fqn: &str) -> EnumWithScope<'a>68 pub fn find_enum(&'a self, fqn: &str) -> EnumWithScope<'a> {
69 match self.find_message_or_enum(fqn) {
70 MessageOrEnumWithScope::Enum(e) => e,
71 _ => panic!("not an enum: {}", fqn),
72 }
73 }
74
75 // find message by fully qualified name
find_message(&'a self, fqn: &str) -> MessageWithScope<'a>76 pub fn find_message(&'a self, fqn: &str) -> MessageWithScope<'a> {
77 match self.find_message_or_enum(fqn) {
78 MessageOrEnumWithScope::Message(m) => m,
79 _ => panic!("not a message: {}", fqn),
80 }
81 }
82
83 // find message or enum by fully qualified name
find_message_or_enum(&'a self, fqn: &str) -> MessageOrEnumWithScope<'a>84 pub fn find_message_or_enum(&'a self, fqn: &str) -> MessageOrEnumWithScope<'a> {
85 assert!(fqn.starts_with("."), "name must start with dot: {}", fqn);
86 let fqn1 = &fqn[1..];
87 self.packages()
88 .into_iter()
89 .flat_map(|p| {
90 (if p.get_package().is_empty() {
91 p.find_message_or_enum(fqn1)
92 } else if fqn1.starts_with(&(p.get_package().to_string() + ".")) {
93 let remaining = &fqn1[(p.get_package().len() + 1)..];
94 p.find_message_or_enum(remaining)
95 } else {
96 None
97 })
98 .into_iter()
99 })
100 .next()
101 .expect(&format!("enum not found by name: {}", fqn))
102 }
103 }
104
105 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
106 pub enum Syntax {
107 PROTO2,
108 PROTO3,
109 }
110
111 impl Syntax {
parse(s: &str) -> Self112 pub fn parse(s: &str) -> Self {
113 match s {
114 "" | "proto2" => Syntax::PROTO2,
115 "proto3" => Syntax::PROTO3,
116 _ => panic!("unsupported syntax value: {:?}", s),
117 }
118 }
119 }
120
121 #[derive(Clone)]
122 pub struct FileScope<'a> {
123 pub file_descriptor: &'a FileDescriptorProto,
124 }
125
126 impl<'a> FileScope<'a> {
get_package(&self) -> &'a str127 fn get_package(&self) -> &'a str {
128 self.file_descriptor.get_package()
129 }
130
syntax(&self) -> Syntax131 pub fn syntax(&self) -> Syntax {
132 Syntax::parse(self.file_descriptor.get_syntax())
133 }
134
to_scope(&self) -> Scope<'a>135 pub fn to_scope(&self) -> Scope<'a> {
136 Scope {
137 file_scope: self.clone(),
138 path: Vec::new(),
139 }
140 }
141
find_message_or_enum(&self, name: &str) -> Option<MessageOrEnumWithScope<'a>>142 fn find_message_or_enum(&self, name: &str) -> Option<MessageOrEnumWithScope<'a>> {
143 assert!(!name.starts_with("."));
144 self.find_messages_and_enums()
145 .into_iter()
146 .filter(|e| e.name_to_package() == name)
147 .next()
148 }
149
150 // find all enums in given file descriptor
find_enums(&self) -> Vec<EnumWithScope<'a>>151 pub fn find_enums(&self) -> Vec<EnumWithScope<'a>> {
152 let mut r = Vec::new();
153
154 self.to_scope().walk_scopes(|scope| {
155 r.extend(scope.get_enums());
156 });
157
158 r
159 }
160
161 // find all messages in given file descriptor
find_messages(&self) -> Vec<MessageWithScope<'a>>162 pub fn find_messages(&self) -> Vec<MessageWithScope<'a>> {
163 let mut r = Vec::new();
164
165 self.to_scope().walk_scopes(|scope| {
166 r.extend(scope.get_messages());
167 });
168
169 r
170 }
171
172 // find all messages and enums in given file descriptor
find_messages_and_enums(&self) -> Vec<MessageOrEnumWithScope<'a>>173 pub fn find_messages_and_enums(&self) -> Vec<MessageOrEnumWithScope<'a>> {
174 let mut r = Vec::new();
175
176 self.to_scope().walk_scopes(|scope| {
177 r.extend(scope.get_messages_and_enums());
178 });
179
180 r
181 }
182 }
183
184 #[derive(Clone)]
185 pub struct Scope<'a> {
186 pub file_scope: FileScope<'a>,
187 pub path: Vec<&'a DescriptorProto>,
188 }
189
190 impl<'a> Scope<'a> {
get_file_descriptor(&self) -> &'a FileDescriptorProto191 pub fn get_file_descriptor(&self) -> &'a FileDescriptorProto {
192 self.file_scope.file_descriptor
193 }
194
195 // get message descriptors in this scope
get_message_descriptors(&self) -> &'a [DescriptorProto]196 fn get_message_descriptors(&self) -> &'a [DescriptorProto] {
197 if self.path.is_empty() {
198 self.file_scope.file_descriptor.get_message_type()
199 } else {
200 self.path.last().unwrap().get_nested_type()
201 }
202 }
203
204 // get enum descriptors in this scope
get_enum_descriptors(&self) -> &'a [EnumDescriptorProto]205 fn get_enum_descriptors(&self) -> &'a [EnumDescriptorProto] {
206 if self.path.is_empty() {
207 self.file_scope.file_descriptor.get_enum_type()
208 } else {
209 self.path.last().unwrap().get_enum_type()
210 }
211 }
212
213 // get messages with attached scopes in this scope
get_messages(&self) -> Vec<MessageWithScope<'a>>214 pub fn get_messages(&self) -> Vec<MessageWithScope<'a>> {
215 self.get_message_descriptors()
216 .iter()
217 .map(|m| MessageWithScope {
218 scope: self.clone(),
219 message: m,
220 })
221 .collect()
222 }
223
224 // get enums with attached scopes in this scope
get_enums(&self) -> Vec<EnumWithScope<'a>>225 pub fn get_enums(&self) -> Vec<EnumWithScope<'a>> {
226 self.get_enum_descriptors()
227 .iter()
228 .map(|e| EnumWithScope {
229 scope: self.clone(),
230 en: e,
231 })
232 .collect()
233 }
234
235 // get messages and enums with attached scopes in this scope
get_messages_and_enums(&self) -> Vec<MessageOrEnumWithScope<'a>>236 pub fn get_messages_and_enums(&self) -> Vec<MessageOrEnumWithScope<'a>> {
237 self.get_messages()
238 .into_iter()
239 .map(|m| MessageOrEnumWithScope::Message(m))
240 .chain(
241 self.get_enums()
242 .into_iter()
243 .map(|m| MessageOrEnumWithScope::Enum(m)),
244 )
245 .collect()
246 }
247
248 // nested scopes, i. e. scopes of nested messages
nested_scopes(&self) -> Vec<Scope<'a>>249 fn nested_scopes(&self) -> Vec<Scope<'a>> {
250 self.get_message_descriptors()
251 .iter()
252 .map(|m| {
253 let mut nested = self.clone();
254 nested.path.push(m);
255 nested
256 })
257 .collect()
258 }
259
walk_scopes_impl<F: FnMut(&Scope<'a>)>(&self, callback: &mut F)260 fn walk_scopes_impl<F: FnMut(&Scope<'a>)>(&self, callback: &mut F) {
261 (*callback)(self);
262
263 for nested in self.nested_scopes() {
264 nested.walk_scopes_impl(callback);
265 }
266 }
267
268 // apply callback for this scope and all nested scopes
walk_scopes<F>(&self, mut callback: F) where F: FnMut(&Scope<'a>),269 fn walk_scopes<F>(&self, mut callback: F)
270 where
271 F: FnMut(&Scope<'a>),
272 {
273 self.walk_scopes_impl(&mut callback);
274 }
275
prefix(&self) -> String276 pub fn prefix(&self) -> String {
277 if self.path.is_empty() {
278 "".to_string()
279 } else {
280 let v: Vec<&'a str> = self.path.iter().map(|m| m.get_name()).collect();
281 let mut r = v.join(".");
282 r.push_str(".");
283 r
284 }
285 }
286
287 // rust type name prefix for this scope
rust_prefix(&self) -> String288 pub fn rust_prefix(&self) -> String {
289 self.prefix().replace(".", "_")
290 }
291 }
292
293 pub trait WithScope<'a> {
get_scope(&self) -> &Scope<'a>294 fn get_scope(&self) -> &Scope<'a>;
295
get_file_descriptor(&self) -> &'a FileDescriptorProto296 fn get_file_descriptor(&self) -> &'a FileDescriptorProto {
297 self.get_scope().get_file_descriptor()
298 }
299
300 // message or enum name
get_name(&self) -> &'a str301 fn get_name(&self) -> &'a str;
302
escape_prefix(&self) -> &'static str303 fn escape_prefix(&self) -> &'static str;
304
name_to_package(&self) -> String305 fn name_to_package(&self) -> String {
306 let mut r = self.get_scope().prefix();
307 r.push_str(self.get_name());
308 r
309 }
310
311 /// Return absolute name starting with dot
name_absolute(&self) -> String312 fn name_absolute(&self) -> String {
313 let mut r = String::new();
314 r.push_str(".");
315 let package = self.get_file_descriptor().get_package();
316 if !package.is_empty() {
317 r.push_str(package);
318 r.push_str(".");
319 }
320 r.push_str(&self.name_to_package());
321 r
322 }
323
324 // rust type name of this descriptor
rust_name(&self) -> String325 fn rust_name(&self) -> String {
326 let mut r = self.get_scope().rust_prefix();
327 // Only escape if prefix is not empty
328 if r.is_empty() && rust::is_rust_keyword(self.get_name()) {
329 r.push_str(self.escape_prefix());
330 }
331 r.push_str(self.get_name());
332 r
333 }
334
335 // fully-qualified name of this type
rust_fq_name(&self) -> String336 fn rust_fq_name(&self) -> String {
337 format!(
338 "{}::{}",
339 proto_path_to_rust_mod(self.get_scope().get_file_descriptor().get_name()),
340 self.rust_name()
341 )
342 }
343 }
344
345 #[derive(Clone)]
346 pub struct MessageWithScope<'a> {
347 pub scope: Scope<'a>,
348 pub message: &'a DescriptorProto,
349 }
350
351 impl<'a> WithScope<'a> for MessageWithScope<'a> {
get_scope(&self) -> &Scope<'a>352 fn get_scope(&self) -> &Scope<'a> {
353 &self.scope
354 }
355
escape_prefix(&self) -> &'static str356 fn escape_prefix(&self) -> &'static str {
357 "message_"
358 }
359
get_name(&self) -> &'a str360 fn get_name(&self) -> &'a str {
361 self.message.get_name()
362 }
363 }
364
365 impl<'a> MessageWithScope<'a> {
into_scope(mut self) -> Scope<'a>366 pub fn into_scope(mut self) -> Scope<'a> {
367 self.scope.path.push(self.message);
368 self.scope
369 }
370
to_scope(&self) -> Scope<'a>371 pub fn to_scope(&self) -> Scope<'a> {
372 self.clone().into_scope()
373 }
374
fields(&self) -> Vec<FieldWithContext<'a>>375 pub fn fields(&self) -> Vec<FieldWithContext<'a>> {
376 self.message
377 .get_field()
378 .iter()
379 .map(|f| FieldWithContext {
380 field: f,
381 message: self.clone(),
382 })
383 .collect()
384 }
385
oneofs(&self) -> Vec<OneofWithContext<'a>>386 pub fn oneofs(&self) -> Vec<OneofWithContext<'a>> {
387 self.message
388 .get_oneof_decl()
389 .iter()
390 .enumerate()
391 .map(|(index, oneof)| OneofWithContext {
392 message: self.clone(),
393 oneof: &oneof,
394 index: index as u32,
395 })
396 .collect()
397 }
398
oneof_by_index(&self, index: u32) -> OneofWithContext<'a>399 pub fn oneof_by_index(&self, index: u32) -> OneofWithContext<'a> {
400 self.oneofs().swap_remove(index as usize)
401 }
402
403 /// Pair of (key, value) if this message is map entry
map_entry(&'a self) -> Option<(FieldWithContext<'a>, FieldWithContext<'a>)>404 pub fn map_entry(&'a self) -> Option<(FieldWithContext<'a>, FieldWithContext<'a>)> {
405 if self.message.get_options().get_map_entry() {
406 let key = self
407 .fields()
408 .into_iter()
409 .find(|f| f.field.get_number() == 1)
410 .unwrap();
411 let value = self
412 .fields()
413 .into_iter()
414 .find(|f| f.field.get_number() == 2)
415 .unwrap();
416 Some((key, value))
417 } else {
418 None
419 }
420 }
421 }
422
423 #[derive(Clone)]
424 pub struct EnumWithScope<'a> {
425 pub scope: Scope<'a>,
426 pub en: &'a EnumDescriptorProto,
427 }
428
429 impl<'a> EnumWithScope<'a> {
430 // enum values
values(&'a self) -> &'a [EnumValueDescriptorProto]431 pub fn values(&'a self) -> &'a [EnumValueDescriptorProto] {
432 self.en.get_value()
433 }
434
435 // find enum value by name
value_by_name(&'a self, name: &str) -> &'a EnumValueDescriptorProto436 pub fn value_by_name(&'a self, name: &str) -> &'a EnumValueDescriptorProto {
437 self.en
438 .get_value()
439 .into_iter()
440 .find(|v| v.get_name() == name)
441 .unwrap()
442 }
443 }
444
445 pub trait EnumValueDescriptorEx {
rust_name(&self) -> String446 fn rust_name(&self) -> String;
447 }
448
449 impl EnumValueDescriptorEx for EnumValueDescriptorProto {
rust_name(&self) -> String450 fn rust_name(&self) -> String {
451 let mut r = String::new();
452 if rust::is_rust_keyword(self.get_name()) {
453 r.push_str("value_");
454 }
455 r.push_str(self.get_name());
456 r
457 }
458 }
459
460 impl<'a> WithScope<'a> for EnumWithScope<'a> {
get_scope(&self) -> &Scope<'a>461 fn get_scope(&self) -> &Scope<'a> {
462 &self.scope
463 }
464
escape_prefix(&self) -> &'static str465 fn escape_prefix(&self) -> &'static str {
466 "enum_"
467 }
468
get_name(&self) -> &'a str469 fn get_name(&self) -> &'a str {
470 self.en.get_name()
471 }
472 }
473
474 pub enum MessageOrEnumWithScope<'a> {
475 Message(MessageWithScope<'a>),
476 Enum(EnumWithScope<'a>),
477 }
478
479 impl<'a> WithScope<'a> for MessageOrEnumWithScope<'a> {
get_scope(&self) -> &Scope<'a>480 fn get_scope(&self) -> &Scope<'a> {
481 match self {
482 &MessageOrEnumWithScope::Message(ref m) => m.get_scope(),
483 &MessageOrEnumWithScope::Enum(ref e) => e.get_scope(),
484 }
485 }
486
escape_prefix(&self) -> &'static str487 fn escape_prefix(&self) -> &'static str {
488 match self {
489 &MessageOrEnumWithScope::Message(ref m) => m.escape_prefix(),
490 &MessageOrEnumWithScope::Enum(ref e) => e.escape_prefix(),
491 }
492 }
493
get_name(&self) -> &'a str494 fn get_name(&self) -> &'a str {
495 match self {
496 &MessageOrEnumWithScope::Message(ref m) => m.get_name(),
497 &MessageOrEnumWithScope::Enum(ref e) => e.get_name(),
498 }
499 }
500 }
501
502 pub trait FieldDescriptorProtoExt {
rust_name(&self) -> String503 fn rust_name(&self) -> String;
504 }
505
506 impl FieldDescriptorProtoExt for FieldDescriptorProto {
rust_name(&self) -> String507 fn rust_name(&self) -> String {
508 if rust::is_rust_keyword(self.get_name()) {
509 format!("field_{}", self.get_name())
510 } else {
511 self.get_name().to_string()
512 }
513 }
514 }
515
516 #[derive(Clone)]
517 pub struct FieldWithContext<'a> {
518 pub field: &'a FieldDescriptorProto,
519 pub message: MessageWithScope<'a>,
520 }
521
522 impl<'a> FieldWithContext<'a> {
523 #[doc(hidden)]
is_oneof(&self) -> bool524 pub fn is_oneof(&self) -> bool {
525 self.field.has_oneof_index()
526 }
527
oneof(&self) -> Option<OneofWithContext<'a>>528 pub fn oneof(&self) -> Option<OneofWithContext<'a>> {
529 if self.is_oneof() {
530 Some(
531 self.message
532 .oneof_by_index(self.field.get_oneof_index() as u32),
533 )
534 } else {
535 None
536 }
537 }
538
number(&self) -> u32539 pub fn number(&self) -> u32 {
540 self.field.get_number() as u32
541 }
542
543 /// Shortcut
name(&self) -> &str544 pub fn name(&self) -> &str {
545 self.field.get_name()
546 }
547
548 // field name in generated code
549 #[deprecated]
rust_name(&self) -> String550 pub fn rust_name(&self) -> String {
551 self.field.rust_name()
552 }
553
554 // From field to file root
containing_messages(&self) -> Vec<&'a DescriptorProto>555 pub fn containing_messages(&self) -> Vec<&'a DescriptorProto> {
556 let mut r = Vec::new();
557 r.push(self.message.message);
558 r.extend(self.message.scope.path.iter().rev());
559 r
560 }
561 }
562
563 #[derive(Clone)]
564 pub struct OneofVariantWithContext<'a> {
565 pub oneof: &'a OneofWithContext<'a>,
566 pub field: &'a FieldDescriptorProto,
567 }
568
569 #[derive(Clone)]
570 pub struct OneofWithContext<'a> {
571 pub oneof: &'a OneofDescriptorProto,
572 pub index: u32,
573 pub message: MessageWithScope<'a>,
574 }
575
576 impl<'a> OneofWithContext<'a> {
577 /// Oneof rust name
name(&'a self) -> &'a str578 pub fn name(&'a self) -> &'a str {
579 match self.oneof.get_name() {
580 "type" => "field_type",
581 "box" => "field_box",
582 x => x,
583 }
584 }
585
586 /// rust type name of enum
rust_name(&self) -> String587 pub fn rust_name(&self) -> String {
588 format!(
589 "{}_oneof_{}",
590 self.message.rust_name(),
591 self.oneof.get_name()
592 )
593 }
594
595 /// Oneof variants
variants(&'a self) -> Vec<OneofVariantWithContext<'a>>596 pub fn variants(&'a self) -> Vec<OneofVariantWithContext<'a>> {
597 self.message
598 .fields()
599 .iter()
600 .filter(|f| f.field.has_oneof_index() && f.field.get_oneof_index() == self.index as i32)
601 .map(|f| OneofVariantWithContext {
602 oneof: self,
603 field: &f.field,
604 })
605 .collect()
606 }
607 }
608
609 /// Find message by rust type name
find_message_by_rust_name<'a>( fd: &'a FileDescriptorProto, rust_name: &str, ) -> MessageWithScope<'a>610 pub fn find_message_by_rust_name<'a>(
611 fd: &'a FileDescriptorProto,
612 rust_name: &str,
613 ) -> MessageWithScope<'a> {
614 FileScope {
615 file_descriptor: fd,
616 }
617 .find_messages()
618 .into_iter()
619 .find(|m| m.rust_name() == rust_name)
620 .unwrap()
621 }
622
623 /// Find enum by rust type name
find_enum_by_rust_name<'a>( fd: &'a FileDescriptorProto, rust_name: &str, ) -> EnumWithScope<'a>624 pub fn find_enum_by_rust_name<'a>(
625 fd: &'a FileDescriptorProto,
626 rust_name: &str,
627 ) -> EnumWithScope<'a> {
628 FileScope {
629 file_descriptor: fd,
630 }
631 .find_enums()
632 .into_iter()
633 .find(|e| e.rust_name() == rust_name)
634 .unwrap()
635 }
636
637 #[cfg(test)]
638 mod test {
639
640 use super::proto_path_to_rust_mod;
641
642 #[test]
test_mod_path_proto_ext()643 fn test_mod_path_proto_ext() {
644 assert_eq!("proto", proto_path_to_rust_mod("proto.proto"));
645 }
646
647 #[test]
test_mod_path_unknown_ext()648 fn test_mod_path_unknown_ext() {
649 assert_eq!("proto_proto3", proto_path_to_rust_mod("proto.proto3"));
650 }
651
652 #[test]
test_mod_path_empty_ext()653 fn test_mod_path_empty_ext() {
654 assert_eq!("proto", proto_path_to_rust_mod("proto"));
655 }
656 }
657