1use std::collections::HashSet;
2
3use prost::bytes::Bytes;
4
5use crate::{
6 descriptor::{
7 build::{
8 join_path, resolve_name, to_json_name,
9 visit::{visit, Visitor},
10 DescriptorPoolOffsets, ResolveNameFilter,
11 },
12 error::{DescriptorError, DescriptorErrorKind, Label},
13 find_enum_proto, find_message_proto, tag, to_index,
14 types::{
15 field_descriptor_proto, DescriptorProto, EnumValueDescriptorProto,
16 FieldDescriptorProto, FileDescriptorProto, MethodDescriptorProto,
17 ServiceDescriptorProto,
18 },
19 Definition, DefinitionKind, DescriptorPoolInner, EnumIndex, EnumValueIndex,
20 ExtensionDescriptorInner, ExtensionIndex, FieldDescriptorInner, FieldIndex, FileIndex,
21 Identity, KindIndex, MessageIndex, MethodDescriptorInner, MethodIndex, OneofIndex,
22 ServiceDescriptorInner, ServiceIndex, RESERVED_MESSAGE_FIELD_NUMBERS,
23 VALID_MESSAGE_FIELD_NUMBERS,
24 },
25 Cardinality, Syntax, Value,
26};
27
28impl DescriptorPoolInner {
29 pub(super) fn resolve_names(
30 &mut self,
31 offsets: DescriptorPoolOffsets,
32 files: &[FileDescriptorProto],
33 ) -> Result<(), DescriptorError> {
34 let mut visitor = ResolveVisitor {
35 pool: self,
36 errors: vec![],
37 };
38 visit(offsets, files, &mut visitor);
39 if visitor.errors.is_empty() {
40 Ok(())
41 } else {
42 Err(DescriptorError::new(visitor.errors))
43 }
44 }
45}
46
47struct ResolveVisitor<'a> {
48 pool: &'a mut DescriptorPoolInner,
49 errors: Vec<DescriptorErrorKind>,
50}
51
52impl Visitor for ResolveVisitor<'_> {
53 fn visit_file(&mut self, path: &[i32], index: FileIndex, file: &FileDescriptorProto) {
54 let mut transitive_dependencies = HashSet::with_capacity(file.dependency.len() + 1);
55 transitive_dependencies.insert(index);
56
57 for (i, dependency) in file.dependency.iter().enumerate() {
58 if let Some(&dependency_index) = self.pool.file_names.get(dependency.as_str()) {
59 self.pool.files[index as usize]
60 .dependencies
61 .push(dependency_index);
62
63 transitive_dependencies.insert(dependency_index);
64 self.resolve_public_dependencies(&mut transitive_dependencies, dependency_index);
65 } else {
66 self.errors.push(DescriptorErrorKind::FileNotFound {
67 name: dependency.clone(),
68 found: Label::new(
69 &self.pool.files,
70 "found here",
71 index,
72 join_path(path, &[tag::file::DEPENDENCY, i as i32]),
73 ),
74 });
75 }
76 }
77
78 self.pool.files[index as usize].transitive_dependencies = transitive_dependencies;
79
80 for &public_dependency in &file.public_dependency {
81 if !matches!(usize::try_from(public_dependency), Ok(i) if i < file.dependency.len()) {
82 self.errors.push(DescriptorErrorKind::InvalidImportIndex);
83 }
84 }
85 for &weak_dependency in &file.weak_dependency {
86 if !matches!(usize::try_from(weak_dependency), Ok(i) if i < file.dependency.len()) {
87 self.errors.push(DescriptorErrorKind::InvalidImportIndex);
88 }
89 }
90 }
91
92 fn visit_field(
93 &mut self,
94 path: &[i32],
95 full_name: &str,
96 file: FileIndex,
97 message: MessageIndex,
98 index: FieldIndex,
99 field: &FieldDescriptorProto,
100 ) {
101 debug_assert_eq!(
102 to_index(self.pool.messages[message as usize].fields.len()),
103 index
104 );
105
106 let syntax = self.pool.files[file as usize].syntax;
107
108 self.check_field_number(message, field, file, path);
109
110 let cardinality = match field.label() {
111 field_descriptor_proto::Label::Optional => Cardinality::Optional,
112 field_descriptor_proto::Label::Required => Cardinality::Required,
113 field_descriptor_proto::Label::Repeated => Cardinality::Repeated,
114 };
115
116 let kind =
117 self.resolve_field_type(field.r#type(), field.type_name(), full_name, file, path);
118
119 let json_name: Box<str> = self.resolve_field_json_name(field, file, path).into();
120
121 let is_packed = cardinality == Cardinality::Repeated
122 && kind.is_some_and(|k| k.is_packable())
123 && (field
124 .options
125 .as_ref()
126 .map_or(syntax == Syntax::Proto3, |o| o.value.packed()));
127
128 let supports_presence = field.proto3_optional()
129 || field.oneof_index.is_some()
130 || (cardinality != Cardinality::Repeated
131 && (kind.is_some_and(|k| k.is_message()) || syntax == Syntax::Proto2));
132
133 let default = kind.and_then(|kind| {
134 self.parse_field_default_value(kind, field.default_value.as_deref(), file, path)
135 });
136
137 let message = &mut self.pool.messages[message as usize];
138
139 let oneof = field.oneof_index.and_then(|oneof_index| {
140 if oneof_index < 0 || oneof_index as usize >= message.oneofs.len() {
141 self.errors.push(DescriptorErrorKind::InvalidOneofIndex);
142 None
143 } else {
144 message.oneofs[oneof_index as usize].fields.push(index);
145 Some(oneof_index as OneofIndex)
146 }
147 });
148
149 message.fields.push(FieldDescriptorInner {
150 id: Identity::new(file, path, full_name, field.name()),
151 number: field.number() as u32,
152 kind: kind.unwrap_or(KindIndex::Double),
153 oneof,
154 is_packed,
155 supports_presence,
156 json_name: json_name.clone(),
157 cardinality,
158 default,
159 });
160 if let Some(existing) = message.field_numbers.insert(field.number() as u32, index) {
161 self.errors.push(DescriptorErrorKind::DuplicateFieldNumber {
162 number: field.number() as u32,
163 first: Label::new(
164 &self.pool.files,
165 "first defined here",
166 file,
167 join_path(
168 &message.fields[existing as usize].id.path,
169 &[tag::field::NUMBER],
170 ),
171 ),
172 second: Label::new(
173 &self.pool.files,
174 "defined again here",
175 file,
176 join_path(path, &[tag::field::NUMBER]),
177 ),
178 });
179 }
180 if let Some(existing) = message.field_names.insert(field.name().into(), index) {
181 self.errors.push(DescriptorErrorKind::DuplicateName {
182 name: full_name.to_owned(),
183 first: Label::new(
184 &self.pool.files,
185 "first defined here",
186 file,
187 join_path(
188 &message.fields[existing as usize].id.path,
189 &[tag::field::NAME],
190 ),
191 ),
192 second: Label::new(
193 &self.pool.files,
194 "defined again here",
195 file,
196 join_path(path, &[tag::field::NAME]),
197 ),
198 });
199 }
200 if let Some(existing) = message.field_json_names.insert(json_name, index) {
201 self.errors
202 .push(DescriptorErrorKind::DuplicateFieldJsonName {
203 name: field.json_name().to_owned(),
204 first: Label::new(
205 &self.pool.files,
206 "first defined here",
207 file,
208 join_path(
209 &message.fields[existing as usize].id.path,
210 &[tag::field::NAME],
211 ),
212 ),
213 second: Label::new(
214 &self.pool.files,
215 "defined again here",
216 file,
217 join_path(path, &[tag::field::NAME]),
218 ),
219 });
220 }
221 }
222
223 fn visit_service(
224 &mut self,
225 path: &[i32],
226 full_name: &str,
227 file: FileIndex,
228 index: ServiceIndex,
229 service: &ServiceDescriptorProto,
230 ) {
231 debug_assert_eq!(to_index(self.pool.services.len()), index);
232
233 self.pool.services.push(ServiceDescriptorInner {
234 id: Identity::new(file, path, full_name, service.name()),
235 methods: Vec::with_capacity(service.method.len()),
236 });
237 }
238
239 fn visit_method(
240 &mut self,
241 path: &[i32],
242 full_name: &str,
243 file: FileIndex,
244 service: ServiceIndex,
245 index: MethodIndex,
246 method: &MethodDescriptorProto,
247 ) {
248 debug_assert_eq!(
249 to_index(self.pool.services[service as usize].methods.len()),
250 index
251 );
252
253 let input = self
254 .find_message(
255 full_name,
256 method.input_type(),
257 file,
258 path,
259 tag::method::INPUT_TYPE,
260 )
261 .unwrap_or(MessageIndex::MAX);
262 let output = self
263 .find_message(
264 full_name,
265 method.output_type(),
266 file,
267 path,
268 tag::method::OUTPUT_TYPE,
269 )
270 .unwrap_or(MessageIndex::MAX);
271
272 self.pool.services[service as usize]
273 .methods
274 .push(MethodDescriptorInner {
275 id: Identity::new(file, path, full_name, method.name()),
276 input,
277 output,
278 });
279 }
280
281 fn visit_enum_value(
282 &mut self,
283 path: &[i32],
284 full_name: &str,
285 file: FileIndex,
286 enum_index: EnumIndex,
287 index: EnumValueIndex,
288 value: &EnumValueDescriptorProto,
289 ) {
290 self.check_enum_number(enum_index, value, file, path);
291
292 let enum_ = &mut self.pool.enums[enum_index as usize];
293
294 let value_numbers_index = match enum_
295 .value_numbers
296 .binary_search_by(|(number, _)| number.cmp(&value.number()))
297 {
298 Ok(existing_index) => {
299 if !enum_.allow_alias {
300 let existing = enum_.value_numbers[existing_index].1;
301 self.errors.push(DescriptorErrorKind::DuplicateEnumNumber {
302 number: value.number(),
303 first: Label::new(
304 &self.pool.files,
305 "first defined here",
306 file,
307 join_path(
308 &enum_.values[existing as usize].id.path,
309 &[tag::enum_value::NUMBER],
310 ),
311 ),
312 second: Label::new(
313 &self.pool.files,
314 "defined again here",
315 file,
316 join_path(path, &[tag::enum_value::NUMBER]),
317 ),
318 });
319 }
320 existing_index
321 }
322 Err(index) => index,
323 };
324 enum_
325 .value_numbers
326 .insert(value_numbers_index, (value.number(), index));
327
328 if let Some(existing) = enum_.value_names.insert(value.name().into(), index) {
329 self.errors.push(DescriptorErrorKind::DuplicateName {
330 name: full_name.to_owned(),
331 first: Label::new(
332 &self.pool.files,
333 "first defined here",
334 file,
335 join_path(
336 &enum_.values[existing as usize].id.path,
337 &[tag::enum_value::NAME],
338 ),
339 ),
340 second: Label::new(
341 &self.pool.files,
342 "defined again here",
343 file,
344 join_path(path, &[tag::enum_value::NAME]),
345 ),
346 });
347 }
348 }
349
350 fn visit_extension(
351 &mut self,
352 path: &[i32],
353 full_name: &str,
354 file: FileIndex,
355 parent_message: Option<MessageIndex>,
356 index: ExtensionIndex,
357 extension: &FieldDescriptorProto,
358 ) {
359 debug_assert_eq!(to_index(self.pool.extensions.len()), index);
360
361 let extendee = self.find_message(
362 full_name,
363 extension.extendee(),
364 file,
365 path,
366 tag::field::EXTENDEE,
367 );
368 if let Some(extendee) = extendee {
369 self.pool.messages[extendee as usize].extensions.push(index);
370
371 self.check_field_number(extendee, extension, file, path);
372 }
373
374 let syntax = self.pool.files[file as usize].syntax;
375
376 let cardinality = match extension.label() {
377 field_descriptor_proto::Label::Optional => Cardinality::Optional,
378 field_descriptor_proto::Label::Required => Cardinality::Required,
379 field_descriptor_proto::Label::Repeated => Cardinality::Repeated,
380 };
381
382 let kind = self.resolve_field_type(
383 extension.r#type(),
384 extension.type_name(),
385 full_name,
386 file,
387 path,
388 );
389
390 self.resolve_field_json_name(extension, file, path);
391
392 let is_packed = cardinality == Cardinality::Repeated
393 && kind.is_some_and(|k| k.is_packable())
394 && (extension
395 .options
396 .as_ref()
397 .map_or(syntax == Syntax::Proto3, |o| o.value.packed()));
398
399 let default = kind.and_then(|kind| {
400 self.parse_field_default_value(kind, extension.default_value.as_deref(), file, path)
401 });
402
403 self.pool.extensions.push(ExtensionDescriptorInner {
404 id: Identity::new(file, path, full_name, extension.name()),
405 parent: parent_message,
406 number: extension.number() as u32,
407 json_name: format!("[{}]", full_name).into(),
408 extendee: extendee.unwrap_or(MessageIndex::MAX),
409 kind: kind.unwrap_or(KindIndex::Double),
410 is_packed,
411 cardinality,
412 default,
413 });
414 }
415}
416
417impl ResolveVisitor<'_> {
418 fn resolve_public_dependencies(&self, dependencies: &mut HashSet<FileIndex>, index: FileIndex) {
419 let file = &self.pool.files[index as usize];
420
421 for (i, dependency) in file.raw.dependency.iter().enumerate() {
422 if let Some(&dependency_index) = self.pool.file_names.get(dependency.as_str()) {
423 if file.raw.public_dependency.contains(&(i as i32))
424 && !dependencies.insert(dependency_index)
425 {
426 self.resolve_public_dependencies(dependencies, dependency_index);
427 }
428 }
429 }
430 }
431
432 fn check_field_number(
433 &mut self,
434 message: MessageIndex,
435 field: &FieldDescriptorProto,
436 file: FileIndex,
437 path: &[i32],
438 ) {
439 if !VALID_MESSAGE_FIELD_NUMBERS.contains(&field.number())
440 || RESERVED_MESSAGE_FIELD_NUMBERS.contains(&field.number())
441 {
442 self.errors.push(DescriptorErrorKind::InvalidFieldNumber {
443 number: field.number(),
444 found: Label::new(
445 &self.pool.files,
446 "defined here",
447 file,
448 join_path(path, &[tag::field::NUMBER]),
449 ),
450 });
451 }
452
453 let message = &self.pool.messages[message as usize];
454 let message_proto = find_message_proto(
455 &self.pool.files[message.id.file as usize].raw,
456 &message.id.path,
457 );
458 for (i, range) in message_proto.reserved_range.iter().enumerate() {
459 if range.start() <= field.number() && field.number() < range.end() {
460 self.errors
461 .push(DescriptorErrorKind::FieldNumberInReservedRange {
462 number: field.number(),
463 range: range.start()..range.end(),
464 defined: Label::new(
465 &self.pool.files,
466 "reserved range defined here",
467 message.id.file,
468 join_path(&message.id.path, &[tag::message::RESERVED_RANGE, i as i32]),
469 ),
470 found: Label::new(
471 &self.pool.files,
472 "defined here",
473 file,
474 join_path(path, &[tag::field::NUMBER]),
475 ),
476 });
477 }
478 }
479
480 let extension_range = message_proto
481 .extension_range
482 .iter()
483 .enumerate()
484 .find(|(_, range)| range.start() <= field.number() && field.number() < range.end());
485 match (&field.extendee, extension_range) {
486 (None, None) | (Some(_), Some(_)) => (),
487 (None, Some((i, range))) => {
488 self.errors
489 .push(DescriptorErrorKind::FieldNumberInExtensionRange {
490 number: field.number(),
491 range: range.start()..range.end(),
492 defined: Label::new(
493 &self.pool.files,
494 "extension range defined here",
495 message.id.file,
496 join_path(&message.id.path, &[tag::message::EXTENSION_RANGE, i as i32]),
497 ),
498 found: Label::new(
499 &self.pool.files,
500 "defined here",
501 file,
502 join_path(path, &[tag::field::NUMBER]),
503 ),
504 });
505 }
506 (Some(_), None) => {
507 self.errors
508 .push(DescriptorErrorKind::ExtensionNumberOutOfRange {
509 number: field.number(),
510 message: message.id.full_name().to_owned(),
511 found: Label::new(
512 &self.pool.files,
513 "defined here",
514 file,
515 join_path(path, &[tag::field::NUMBER]),
516 ),
517 });
518 }
519 }
520 }
521
522 fn check_enum_number(
523 &mut self,
524 enum_: EnumIndex,
525 value: &EnumValueDescriptorProto,
526 file: FileIndex,
527 path: &[i32],
528 ) {
529 let enum_ = &self.pool.enums[enum_ as usize];
530 let enum_proto =
531 find_enum_proto(&self.pool.files[enum_.id.file as usize].raw, &enum_.id.path);
532 for (i, range) in enum_proto.reserved_range.iter().enumerate() {
533 if range.start() <= value.number() && value.number() <= range.end() {
534 self.errors
535 .push(DescriptorErrorKind::EnumNumberInReservedRange {
536 number: value.number(),
537 range: range.start()..=range.end(),
538 defined: Label::new(
539 &self.pool.files,
540 "reserved range defined here",
541 enum_.id.file,
542 join_path(&enum_.id.path, &[tag::enum_::RESERVED_RANGE, i as i32]),
543 ),
544 found: Label::new(
545 &self.pool.files,
546 "defined here",
547 file,
548 join_path(path, &[tag::field::NUMBER]),
549 ),
550 });
551 }
552 }
553 }
554
555 fn resolve_field_json_name<'b>(
556 &'b mut self,
557 field: &'b FieldDescriptorProto,
558 file: FileIndex,
559 path: &[i32],
560 ) -> &'b str {
561 if let Some(json_name) = &field.json_name {
562 json_name
563 } else {
564 let field = find_file_field_proto_mut(&mut self.pool.files[file as usize].raw, path);
565 field.json_name.insert(to_json_name(field.name()))
566 }
567 }
568
569 fn resolve_field_type(
570 &mut self,
571 ty: field_descriptor_proto::Type,
572 ty_name: &str,
573 scope: &str,
574 file: FileIndex,
575 path: &[i32],
576 ) -> Option<KindIndex> {
577 if ty_name.is_empty() {
578 match ty {
579 field_descriptor_proto::Type::Double => Some(KindIndex::Double),
580 field_descriptor_proto::Type::Float => Some(KindIndex::Float),
581 field_descriptor_proto::Type::Int64 => Some(KindIndex::Int64),
582 field_descriptor_proto::Type::Uint64 => Some(KindIndex::Uint64),
583 field_descriptor_proto::Type::Int32 => Some(KindIndex::Int32),
584 field_descriptor_proto::Type::Fixed64 => Some(KindIndex::Fixed64),
585 field_descriptor_proto::Type::Fixed32 => Some(KindIndex::Fixed32),
586 field_descriptor_proto::Type::Bool => Some(KindIndex::Bool),
587 field_descriptor_proto::Type::String => Some(KindIndex::String),
588 field_descriptor_proto::Type::Bytes => Some(KindIndex::Bytes),
589 field_descriptor_proto::Type::Uint32 => Some(KindIndex::Uint32),
590 field_descriptor_proto::Type::Sfixed32 => Some(KindIndex::Sfixed32),
591 field_descriptor_proto::Type::Sfixed64 => Some(KindIndex::Sfixed64),
592 field_descriptor_proto::Type::Sint32 => Some(KindIndex::Sint32),
593 field_descriptor_proto::Type::Sint64 => Some(KindIndex::Sint64),
594 field_descriptor_proto::Type::Group
595 | field_descriptor_proto::Type::Message
596 | field_descriptor_proto::Type::Enum => {
597 self.add_missing_required_field_error(
598 file,
599 join_path(path, &[tag::field::TYPE_NAME]),
600 );
601 None
602 }
603 }
604 } else {
605 let def = self.resolve_name(
606 scope,
607 ty_name,
608 file,
609 path,
610 tag::field::TYPE_NAME,
611 ResolveNameFilter::FieldType,
612 )?;
613 match def.kind {
614 DefinitionKind::Message(message) => {
615 if ty == field_descriptor_proto::Type::Group {
616 Some(KindIndex::Group(message))
617 } else {
618 Some(KindIndex::Message(message))
619 }
620 }
621 DefinitionKind::Enum(enum_) => Some(KindIndex::Enum(enum_)),
622 _ => unreachable!(),
623 }
624 }
625 }
626
627 fn parse_field_default_value(
628 &mut self,
629 kind: KindIndex,
630 default_value: Option<&str>,
631 file: FileIndex,
632 path: &[i32],
633 ) -> Option<Value> {
634 let default_value = default_value?;
635
636 match kind {
637 KindIndex::Double
638 | KindIndex::Float
639 | KindIndex::Int32
640 | KindIndex::Int64
641 | KindIndex::Uint32
642 | KindIndex::Uint64
643 | KindIndex::Sint32
644 | KindIndex::Sint64
645 | KindIndex::Fixed32
646 | KindIndex::Fixed64
647 | KindIndex::Sfixed32
648 | KindIndex::Sfixed64
649 | KindIndex::Bool
650 | KindIndex::String
651 | KindIndex::Bytes => match parse_simple_value(kind, default_value) {
652 Ok(value) => Some(value),
653 Err(_) => {
654 self.errors.push(DescriptorErrorKind::InvalidFieldDefault {
655 value: default_value.to_owned(),
656 kind: format!("{:?}", kind),
657 found: Label::new(
658 &self.pool.files,
659 "found here",
660 file,
661 join_path(path, &[tag::field::DEFAULT_VALUE]),
662 ),
663 });
664 None
665 }
666 },
667 KindIndex::Enum(enum_) => {
668 let enum_ = &self.pool.enums[enum_ as usize];
669 if let Some(value) = enum_.values.iter().find(|v| v.id.name() == default_value) {
670 Some(Value::EnumNumber(value.number))
671 } else {
672 self.errors.push(DescriptorErrorKind::InvalidFieldDefault {
673 value: default_value.to_owned(),
674 kind: enum_.id.full_name().to_owned(),
675 found: Label::new(
676 &self.pool.files,
677 "found here",
678 file,
679 join_path(path, &[tag::field::DEFAULT_VALUE]),
680 ),
681 });
682 None
683 }
684 }
685 _ => {
686 self.errors.push(DescriptorErrorKind::InvalidFieldDefault {
687 value: default_value.to_owned(),
688 kind: "message type".to_owned(),
689 found: Label::new(
690 &self.pool.files,
691 "found here",
692 file,
693 join_path(path, &[tag::field::DEFAULT_VALUE]),
694 ),
695 });
696 None
697 }
698 }
699 }
700
701 fn find_message(
702 &mut self,
703 scope: &str,
704 name: &str,
705 file: FileIndex,
706 path1: &[i32],
707 path2: i32,
708 ) -> Option<MessageIndex> {
709 let def = self.resolve_name(scope, name, file, path1, path2, ResolveNameFilter::Message)?;
710 match def.kind {
711 DefinitionKind::Message(message) => Some(message),
712 _ => unreachable!(),
713 }
714 }
715
716 fn resolve_name(
717 &mut self,
718 scope: &str,
719 name: &str,
720 file: FileIndex,
721 path: &[i32],
722 tag: i32,
723 filter: ResolveNameFilter,
724 ) -> Option<&Definition> {
725 let (type_name, def) = match resolve_name(
726 &self.pool.files[file as usize].transitive_dependencies,
727 &self.pool.names,
728 scope,
729 name,
730 filter,
731 )
732 .into_result(name, &self.pool.files, file, path, &[tag])
733 {
734 Ok((type_name, def)) => (type_name, def),
735 Err(err) => {
736 self.errors.push(err);
737 return None;
738 }
739 };
740
741 let ty = if matches!(
742 def,
743 Definition {
744 kind: DefinitionKind::Message(_),
745 ..
746 }
747 ) {
748 field_descriptor_proto::Type::Message
749 } else {
750 field_descriptor_proto::Type::Enum
751 };
752 set_type_name(
753 &mut self.pool.files[file as usize].raw,
754 path,
755 tag,
756 format!(".{}", type_name),
757 ty,
758 );
759 Some(def)
760 }
761
762 fn add_missing_required_field_error(&mut self, file: FileIndex, path: Box<[i32]>) {
763 self.errors.push(DescriptorErrorKind::MissingRequiredField {
764 label: Label::new(&self.pool.files, "found here", file, path),
765 });
766 }
767}
768
769fn parse_simple_value(
770 kind: KindIndex,
771 value: &str,
772) -> Result<Value, Box<dyn std::error::Error + Send + Sync>> {
773 let value = match kind {
774 KindIndex::Double => value.parse().map(Value::F64)?,
775 KindIndex::Float => value.parse().map(Value::F32)?,
776 KindIndex::Int32 | KindIndex::Sint32 | KindIndex::Sfixed32 => {
777 value.parse().map(Value::I32)?
778 }
779 KindIndex::Int64 | KindIndex::Sint64 | KindIndex::Sfixed64 => {
780 value.parse().map(Value::I64)?
781 }
782 KindIndex::Uint32 | KindIndex::Fixed32 => value.parse().map(Value::U32)?,
783 KindIndex::Uint64 | KindIndex::Fixed64 => value.parse().map(Value::U64)?,
784 KindIndex::Bool => value.parse().map(Value::Bool)?,
785 KindIndex::String => Value::String(value.to_owned()),
786 KindIndex::Bytes => unescape_c_escape_string(value).map(Value::Bytes)?,
787 KindIndex::Enum(_) | KindIndex::Message(_) | KindIndex::Group(_) => unreachable!(),
788 };
789
790 Ok(value)
791}
792
793fn unescape_c_escape_string(s: &str) -> Result<Bytes, &'static str> {
797 let src = s.as_bytes();
798 let len = src.len();
799 let mut dst = Vec::new();
800
801 let mut p = 0;
802
803 while p < len {
804 if src[p] != b'\\' {
805 dst.push(src[p]);
806 p += 1;
807 } else {
808 p += 1;
809 if p == len {
810 return Err("missing escape character");
811 }
812 match src[p] {
813 b'a' => {
814 dst.push(0x07);
815 p += 1;
816 }
817 b'b' => {
818 dst.push(0x08);
819 p += 1;
820 }
821 b'f' => {
822 dst.push(0x0C);
823 p += 1;
824 }
825 b'n' => {
826 dst.push(0x0A);
827 p += 1;
828 }
829 b'r' => {
830 dst.push(0x0D);
831 p += 1;
832 }
833 b't' => {
834 dst.push(0x09);
835 p += 1;
836 }
837 b'v' => {
838 dst.push(0x0B);
839 p += 1;
840 }
841 b'\\' => {
842 dst.push(0x5C);
843 p += 1;
844 }
845 b'?' => {
846 dst.push(0x3F);
847 p += 1;
848 }
849 b'\'' => {
850 dst.push(0x27);
851 p += 1;
852 }
853 b'"' => {
854 dst.push(0x22);
855 p += 1;
856 }
857 b'0'..=b'7' => {
858 let mut octal = 0;
859 for _ in 0..3 {
860 if p < len && src[p] >= b'0' && src[p] <= b'7' {
861 octal = octal * 8 + (src[p] - b'0');
862 p += 1;
863 } else {
864 break;
865 }
866 }
867 dst.push(octal);
868 }
869 b'x' | b'X' => {
870 if p + 3 > len {
871 return Err("hex escape must contain two characters");
872 }
873 match u8::from_str_radix(&s[p + 1..p + 3], 16) {
874 Ok(b) => dst.push(b),
875 _ => return Err("invalid hex escape"),
876 }
877 p += 3;
878 }
879 _ => return Err("invalid escape character"),
880 }
881 }
882 }
883 Ok(dst.into())
884}
885
886fn set_type_name(
887 file: &mut FileDescriptorProto,
888 path: &[i32],
889 tag: i32,
890 type_name: String,
891 ty: field_descriptor_proto::Type,
892) {
893 match path[0] {
894 tag::file::SERVICE => {
895 debug_assert_eq!(path.len(), 4);
896 let service = &mut file.service[path[1] as usize];
897 debug_assert_eq!(path[2], tag::service::METHOD);
898 let method = &mut service.method[path[3] as usize];
899 match tag {
900 tag::method::INPUT_TYPE => method.input_type = Some(type_name),
901 tag::method::OUTPUT_TYPE => method.output_type = Some(type_name),
902 p => panic!("unknown path element {}", p),
903 }
904 }
905 tag::file::MESSAGE_TYPE | tag::file::EXTENSION => {
906 let field = find_file_field_proto_mut(file, path);
907 match tag {
908 tag::field::TYPE_NAME => {
909 field.type_name = Some(type_name);
910 if field.r#type() != field_descriptor_proto::Type::Group {
911 field.set_type(ty);
912 }
913 }
914 tag::field::EXTENDEE => field.extendee = Some(type_name),
915 p => panic!("unknown path element {}", p),
916 }
917 }
918 p => panic!("unknown path element {}", p),
919 }
920}
921
922fn find_file_field_proto_mut<'a>(
923 file: &'a mut FileDescriptorProto,
924 path: &[i32],
925) -> &'a mut FieldDescriptorProto {
926 match path[0] {
927 tag::file::MESSAGE_TYPE => {
928 let message = &mut file.message_type[path[1] as usize];
929 find_message_field_proto(message, &path[2..])
930 }
931 tag::file::EXTENSION => {
932 debug_assert_eq!(path.len(), 2);
933 &mut file.extension[path[1] as usize]
934 }
935 p => panic!("unknown path element {}", p),
936 }
937}
938
939fn find_message_field_proto<'a>(
940 message: &'a mut DescriptorProto,
941 path: &[i32],
942) -> &'a mut FieldDescriptorProto {
943 match path[0] {
944 tag::message::FIELD => {
945 debug_assert_eq!(path.len(), 2);
946 &mut message.field[path[1] as usize]
947 }
948 tag::message::EXTENSION => {
949 debug_assert_eq!(path.len(), 2);
950 &mut message.extension[path[1] as usize]
951 }
952 tag::message::NESTED_TYPE => {
953 let nested_message = &mut message.nested_type[path[1] as usize];
954 find_message_field_proto(nested_message, &path[2..])
955 }
956 p => panic!("unknown path element {}", p),
957 }
958}
959
960#[test]
961fn test_unescape_c_escape_string() {
962 assert_eq!(Ok(Bytes::default()), unescape_c_escape_string(""));
963 assert_eq!(
964 Ok(Bytes::from_static(b"hello world")),
965 unescape_c_escape_string("hello world"),
966 );
967 assert_eq!(
968 Ok(Bytes::from_static(b"\0")),
969 unescape_c_escape_string(r"\0"),
970 );
971 assert_eq!(
972 Ok(Bytes::from_static(&[0o012, 0o156])),
973 unescape_c_escape_string(r"\012\156"),
974 );
975 assert_eq!(
976 Ok(Bytes::from_static(&[0x01, 0x02])),
977 unescape_c_escape_string(r"\x01\x02")
978 );
979 assert_eq!(
980 Ok(Bytes::from_static(
981 b"\0\x01\x07\x08\x0C\n\r\t\x0B\\\'\"\xFE?"
982 )),
983 unescape_c_escape_string(r#"\0\001\a\b\f\n\r\t\v\\\'\"\xfe\?"#),
984 );
985 assert_eq!(
986 Err("hex escape must contain two characters"),
987 unescape_c_escape_string(r"\x")
988 );
989 assert_eq!(
990 Err("hex escape must contain two characters"),
991 unescape_c_escape_string(r"\x1")
992 );
993 assert_eq!(
994 Ok(Bytes::from_static(b"\x11")),
995 unescape_c_escape_string(r"\x11"),
996 );
997 assert_eq!(
998 Ok(Bytes::from_static(b"\x111")),
999 unescape_c_escape_string(r"\x111")
1000 );
1001 assert_eq!(
1002 Err("invalid escape character"),
1003 unescape_c_escape_string(r"\w")
1004 );
1005 assert_eq!(Err("invalid hex escape"), unescape_c_escape_string(r"\x__"));
1006}