prost_reflect/descriptor/build/
resolve.rs

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
793/// From https://github.com/tokio-rs/prost/blob/c3b7037a7f2c56cef327b41ca32a8c4e9ce5a41c/prost-build/src/code_generator.rs#L887
794/// Based on [`google::protobuf::UnescapeCEscapeString`][1]
795/// [1]: https://github.com/google/protobuf/blob/3.3.x/src/google/protobuf/stubs/strutil.cc#L312-L322
796fn 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}