prost_reflect/descriptor/
error.rs

1use std::{
2    fmt,
3    ops::{Range, RangeInclusive},
4};
5
6use crate::descriptor::{FileDescriptorInner, FileIndex};
7
8/// An error that may occur while creating a [`DescriptorPool`][crate::DescriptorPool].
9pub struct DescriptorError {
10    errors: Box<[DescriptorErrorKind]>,
11    #[cfg(feature = "miette")]
12    source: Option<miette::NamedSource<String>>,
13}
14
15#[derive(Debug)]
16pub(super) enum DescriptorErrorKind {
17    MissingRequiredField {
18        label: Label,
19    },
20    UnknownSyntax {
21        syntax: String,
22        found: Label,
23    },
24    DuplicateFileName {
25        name: String,
26    },
27    FileNotFound {
28        name: String,
29        found: Label,
30    },
31    InvalidImportIndex,
32    InvalidOneofIndex,
33    DuplicateName {
34        name: String,
35        first: Label,
36        second: Label,
37    },
38    DuplicateFieldNumber {
39        number: u32,
40        #[cfg_attr(not(feature = "miette"), allow(dead_code))]
41        first: Label,
42        second: Label,
43    },
44    DuplicateFieldJsonName {
45        name: String,
46        #[cfg_attr(not(feature = "miette"), allow(dead_code))]
47        first: Label,
48        second: Label,
49    },
50    DuplicateFieldCamelCaseName {
51        first_name: String,
52        second_name: String,
53        #[cfg_attr(not(feature = "miette"), allow(dead_code))]
54        first: Label,
55        second: Label,
56    },
57    InvalidFieldNumber {
58        number: i32,
59        found: Label,
60    },
61    FieldNumberInReservedRange {
62        number: i32,
63        range: Range<i32>,
64        #[cfg_attr(not(feature = "miette"), allow(dead_code))]
65        defined: Label,
66        found: Label,
67    },
68    FieldNumberInExtensionRange {
69        number: i32,
70        range: Range<i32>,
71        #[cfg_attr(not(feature = "miette"), allow(dead_code))]
72        defined: Label,
73        found: Label,
74    },
75    ExtensionNumberOutOfRange {
76        number: i32,
77        message: String,
78        found: Label,
79    },
80    NameNotFound {
81        name: String,
82        found: Label,
83        #[cfg_attr(not(feature = "miette"), allow(dead_code))]
84        help: Option<String>,
85    },
86    NameShadowed {
87        name: String,
88        shadowed_name: String,
89        found: Label,
90        #[cfg_attr(not(feature = "miette"), allow(dead_code))]
91        help: Option<String>,
92    },
93    InvalidType {
94        name: String,
95        expected: String,
96        found: Label,
97        #[cfg_attr(not(feature = "miette"), allow(dead_code))]
98        defined: Label,
99    },
100    InvalidFieldDefault {
101        value: String,
102        kind: String,
103        found: Label,
104    },
105    EmptyEnum {
106        found: Label,
107    },
108    InvalidProto3EnumDefault {
109        found: Label,
110    },
111    DuplicateEnumNumber {
112        number: i32,
113        #[cfg_attr(not(feature = "miette"), allow(dead_code))]
114        first: Label,
115        second: Label,
116    },
117    EnumNumberInReservedRange {
118        number: i32,
119        range: RangeInclusive<i32>,
120        #[cfg_attr(not(feature = "miette"), allow(dead_code))]
121        defined: Label,
122        found: Label,
123    },
124    OptionNotFound {
125        name: String,
126        found: Label,
127    },
128    InvalidOptionType {
129        name: String,
130        ty: String,
131        value: String,
132        is_last: bool,
133        found: Label,
134    },
135    InvalidOptionExtendee {
136        name: String,
137        expected_extendee: String,
138        actual_extendee: String,
139        found: Label,
140    },
141    #[cfg(feature = "text-format")]
142    InvalidMessageOption {
143        name: String,
144        ty: String,
145        found: Label,
146        err: crate::text_format::ParseError,
147    },
148    DuplicateOption {
149        name: String,
150        found: Label,
151    },
152    DecodeFileDescriptorSet {
153        err: prost::DecodeError,
154    },
155}
156
157#[derive(Debug)]
158pub(super) struct Label {
159    file: String,
160    path: Box<[i32]>,
161    span: Option<[i32; 4]>,
162    #[cfg(feature = "miette")]
163    message: String,
164    #[cfg(feature = "miette")]
165    resolved: Option<miette::SourceSpan>,
166}
167
168impl DescriptorError {
169    pub(super) fn new(errors: Vec<DescriptorErrorKind>) -> DescriptorError {
170        debug_assert!(!errors.is_empty());
171        DescriptorError {
172            errors: errors.into(),
173            #[cfg(feature = "miette")]
174            source: None,
175        }
176    }
177
178    /// The primary file in which this error occurred.
179    pub fn file(&self) -> Option<&str> {
180        self.first().label().map(|l| l.file.as_str())
181    }
182
183    /// The 0-based line number at which this error occurred, if available.
184    ///
185    /// This field may be `None` if the error is not associated with a particular source location, or the
186    /// [`source_code_info`](prost_types::FileDescriptorProto::source_code_info) field was not populated for the input file.
187    pub fn line(&self) -> Option<usize> {
188        self.first()
189            .label()
190            .and_then(|l| l.span)
191            .map(|s| s[0] as usize)
192    }
193
194    /// The 0-based column number at which this error occurred, if available.
195    ///
196    /// This field may be `None` if the error is not associated with a particular source location, or the
197    /// [`source_code_info`](prost_types::FileDescriptorProto::source_code_info) field was not populated for the input file.
198    pub fn column(&self) -> Option<usize> {
199        self.first()
200            .label()
201            .and_then(|l| l.span)
202            .map(|s| s[1] as usize)
203    }
204
205    /// Gets the path where this error occurred in the [`FileDescriptorProto`][prost_types::FileDescriptorProto], if available.
206    ///
207    /// See [`path`][prost_types::source_code_info::Location::path] for more details on the structure of the path.
208    pub fn path(&self) -> Option<&[i32]> {
209        self.first().label().map(|l| l.path.as_ref())
210    }
211
212    #[cfg(feature = "miette")]
213    #[cfg_attr(docsrs, doc(cfg(feature = "miette")))]
214    /// Provide source code information for this error.
215    ///
216    /// The source should correspond to the contents of [`file()`][DescriptorError::file].
217    pub fn with_source_code(mut self, source: &str) -> Self {
218        if let Some(file) = self.file() {
219            let file = file.to_owned();
220
221            self.source = Some(miette::NamedSource::new(&file, source.to_owned()));
222            for error in self.errors.as_mut() {
223                error.add_source_code(&file, source);
224            }
225        }
226        self
227    }
228
229    fn first(&self) -> &DescriptorErrorKind {
230        &self.errors[0]
231    }
232}
233
234impl std::error::Error for DescriptorError {
235    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
236        self.first().source()
237    }
238}
239
240impl fmt::Display for DescriptorError {
241    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
242        self.first().fmt(f)
243    }
244}
245
246impl fmt::Debug for DescriptorError {
247    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
248        if let Some(file) = self.file() {
249            write!(f, "{file}:")?;
250            if let (Some(line), Some(column)) = (self.line(), self.column()) {
251                write!(f, "{}:{}:", line + 1, column + 1)?;
252            }
253            write!(f, " ")?;
254        }
255
256        write!(f, "{self}")
257    }
258}
259
260#[cfg(feature = "miette")]
261#[cfg_attr(docsrs, doc(cfg(feature = "miette")))]
262impl miette::Diagnostic for DescriptorError {
263    fn code<'a>(&'a self) -> Option<Box<dyn fmt::Display + 'a>> {
264        self.first().code()
265    }
266
267    fn severity(&self) -> Option<miette::Severity> {
268        self.first().severity()
269    }
270
271    fn help<'a>(&'a self) -> Option<Box<dyn fmt::Display + 'a>> {
272        self.first().help()
273    }
274
275    fn url<'a>(&'a self) -> Option<Box<dyn fmt::Display + 'a>> {
276        self.first().url()
277    }
278
279    fn source_code(&self) -> Option<&dyn miette::SourceCode> {
280        match &self.source {
281            Some(source) => Some(source),
282            None => None,
283        }
284    }
285
286    fn labels(&self) -> Option<Box<dyn Iterator<Item = miette::LabeledSpan> + '_>> {
287        self.first().labels()
288    }
289
290    fn related<'a>(&'a self) -> Option<Box<dyn Iterator<Item = &'a dyn miette::Diagnostic> + 'a>> {
291        if self.errors.len() > 1 {
292            Some(Box::new(
293                self.errors
294                    .iter()
295                    .map(|e| e as &dyn miette::Diagnostic)
296                    .skip(1),
297            ))
298        } else {
299            None
300        }
301    }
302
303    fn diagnostic_source(&self) -> Option<&dyn miette::Diagnostic> {
304        self.first().diagnostic_source()
305    }
306}
307
308impl DescriptorErrorKind {
309    fn label(&self) -> Option<&Label> {
310        match self {
311            DescriptorErrorKind::MissingRequiredField { label } => Some(label),
312            DescriptorErrorKind::UnknownSyntax { found, .. } => Some(found),
313            DescriptorErrorKind::DuplicateFileName { .. } => None,
314            DescriptorErrorKind::FileNotFound { found, .. } => Some(found),
315            DescriptorErrorKind::InvalidImportIndex => None,
316            DescriptorErrorKind::InvalidOneofIndex => None,
317            DescriptorErrorKind::DuplicateName { second, .. } => Some(second),
318            DescriptorErrorKind::DuplicateFieldNumber { second, .. } => Some(second),
319            DescriptorErrorKind::DuplicateFieldJsonName { second, .. } => Some(second),
320            DescriptorErrorKind::DuplicateFieldCamelCaseName { second, .. } => Some(second),
321            DescriptorErrorKind::InvalidFieldNumber { found, .. } => Some(found),
322            DescriptorErrorKind::FieldNumberInReservedRange { found, .. } => Some(found),
323            DescriptorErrorKind::FieldNumberInExtensionRange { found, .. } => Some(found),
324            DescriptorErrorKind::ExtensionNumberOutOfRange { found, .. } => Some(found),
325            DescriptorErrorKind::NameNotFound { found, .. } => Some(found),
326            DescriptorErrorKind::NameShadowed { found, .. } => Some(found),
327            DescriptorErrorKind::InvalidType { found, .. } => Some(found),
328            DescriptorErrorKind::InvalidFieldDefault { found, .. } => Some(found),
329            DescriptorErrorKind::EmptyEnum { found } => Some(found),
330            DescriptorErrorKind::InvalidProto3EnumDefault { found } => Some(found),
331            DescriptorErrorKind::DuplicateEnumNumber { second, .. } => Some(second),
332            DescriptorErrorKind::EnumNumberInReservedRange { found, .. } => Some(found),
333            DescriptorErrorKind::OptionNotFound { found, .. } => Some(found),
334            DescriptorErrorKind::InvalidOptionType { found, .. } => Some(found),
335            DescriptorErrorKind::InvalidOptionExtendee { found, .. } => Some(found),
336            #[cfg(feature = "text-format")]
337            DescriptorErrorKind::InvalidMessageOption { found, .. } => Some(found),
338            DescriptorErrorKind::DuplicateOption { found, .. } => Some(found),
339            DescriptorErrorKind::DecodeFileDescriptorSet { .. } => None,
340        }
341    }
342
343    #[cfg(feature = "miette")]
344    fn add_source_code(&mut self, file: &str, source: &str) {
345        match self {
346            DescriptorErrorKind::MissingRequiredField { label } => {
347                label.resolve_span(file, source);
348            }
349            DescriptorErrorKind::UnknownSyntax { found, .. } => {
350                found.resolve_span(file, source);
351            }
352            DescriptorErrorKind::DuplicateFileName { .. } => {}
353            DescriptorErrorKind::FileNotFound { found, .. } => {
354                found.resolve_span(file, source);
355            }
356            DescriptorErrorKind::InvalidImportIndex => {}
357            DescriptorErrorKind::InvalidOneofIndex => {}
358            DescriptorErrorKind::DuplicateName { first, second, .. } => {
359                first.resolve_span(file, source);
360                second.resolve_span(file, source);
361            }
362            DescriptorErrorKind::DuplicateFieldNumber { first, second, .. } => {
363                first.resolve_span(file, source);
364                second.resolve_span(file, source);
365            }
366            DescriptorErrorKind::DuplicateFieldJsonName { first, second, .. } => {
367                first.resolve_span(file, source);
368                second.resolve_span(file, source);
369            }
370            DescriptorErrorKind::DuplicateFieldCamelCaseName { first, second, .. } => {
371                first.resolve_span(file, source);
372                second.resolve_span(file, source);
373            }
374            DescriptorErrorKind::InvalidFieldNumber { found, .. } => {
375                found.resolve_span(file, source);
376            }
377            DescriptorErrorKind::FieldNumberInReservedRange { defined, found, .. } => {
378                defined.resolve_span(file, source);
379                found.resolve_span(file, source);
380            }
381            DescriptorErrorKind::FieldNumberInExtensionRange { defined, found, .. } => {
382                defined.resolve_span(file, source);
383                found.resolve_span(file, source);
384            }
385            DescriptorErrorKind::ExtensionNumberOutOfRange { found, .. } => {
386                found.resolve_span(file, source);
387            }
388            DescriptorErrorKind::NameNotFound { found, .. } => {
389                found.resolve_span(file, source);
390            }
391            DescriptorErrorKind::NameShadowed { found, .. } => {
392                found.resolve_span(file, source);
393            }
394            DescriptorErrorKind::InvalidType { found, defined, .. } => {
395                found.resolve_span(file, source);
396                defined.resolve_span(file, source);
397            }
398            DescriptorErrorKind::InvalidFieldDefault { found, .. } => {
399                found.resolve_span(file, source);
400            }
401            DescriptorErrorKind::EmptyEnum { found } => {
402                found.resolve_span(file, source);
403            }
404            DescriptorErrorKind::InvalidProto3EnumDefault { found } => {
405                found.resolve_span(file, source);
406            }
407            DescriptorErrorKind::DuplicateEnumNumber { first, second, .. } => {
408                first.resolve_span(file, source);
409                second.resolve_span(file, source);
410            }
411            DescriptorErrorKind::EnumNumberInReservedRange { defined, found, .. } => {
412                found.resolve_span(file, source);
413                defined.resolve_span(file, source);
414            }
415            DescriptorErrorKind::OptionNotFound { found, .. } => {
416                found.resolve_span(file, source);
417            }
418            DescriptorErrorKind::InvalidOptionType { found, .. } => {
419                found.resolve_span(file, source);
420            }
421            DescriptorErrorKind::InvalidOptionExtendee { found, .. } => {
422                found.resolve_span(file, source);
423            }
424            #[cfg(feature = "text-format")]
425            DescriptorErrorKind::InvalidMessageOption { found, .. } => {
426                found.resolve_span(file, source);
427            }
428            DescriptorErrorKind::DuplicateOption { found, .. } => {
429                found.resolve_span(file, source);
430            }
431            DescriptorErrorKind::DecodeFileDescriptorSet { .. } => {}
432        }
433    }
434}
435
436impl std::error::Error for DescriptorErrorKind {
437    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
438        match self {
439            DescriptorErrorKind::DecodeFileDescriptorSet { err } => Some(err),
440            #[cfg(feature = "text-format")]
441            DescriptorErrorKind::InvalidMessageOption { err, .. } => Some(err),
442            _ => None,
443        }
444    }
445}
446
447impl fmt::Display for DescriptorErrorKind {
448    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
449        match self {
450            DescriptorErrorKind::MissingRequiredField { label } => {
451                write!(f, "missing required field at {:?}", label.path)
452            }
453            DescriptorErrorKind::UnknownSyntax { syntax, .. } => {
454                write!(f, "unknown syntax '{syntax}'")
455            }
456            DescriptorErrorKind::DuplicateFileName { name, .. } => {
457                write!(f, "a different file named '{name}' has already been added")
458            }
459            DescriptorErrorKind::FileNotFound { name, .. } => {
460                write!(f, "imported file '{name}' has not been added")
461            }
462            DescriptorErrorKind::InvalidImportIndex => {
463                write!(f, "invalid import index")
464            }
465            DescriptorErrorKind::InvalidOneofIndex => {
466                write!(f, "invalid oneof index")
467            }
468            DescriptorErrorKind::DuplicateName {
469                name,
470                first,
471                second,
472            } => {
473                if first.file == second.file {
474                    write!(f, "name '{name}' is defined twice")
475                } else {
476                    write!(
477                        f,
478                        "name '{}' is already defined in file '{}'",
479                        name, first.file
480                    )
481                }
482            }
483            DescriptorErrorKind::DuplicateFieldNumber { number, .. } => {
484                write!(f, "field number '{number}' is already used")
485            }
486            DescriptorErrorKind::DuplicateFieldJsonName { name, .. } => {
487                write!(f, "a field with JSON name '{name}' is already defined")
488            }
489            DescriptorErrorKind::DuplicateFieldCamelCaseName {
490                first_name,
491                second_name,
492                ..
493            } => {
494                write!(
495                    f,
496                    "camel-case name of field '{first_name}' conflicts with field '{second_name}'"
497                )
498            }
499            DescriptorErrorKind::InvalidFieldNumber { number, .. } => {
500                write!(f, "invalid field number '{number}'")
501            }
502            DescriptorErrorKind::FieldNumberInReservedRange { number, range, .. } => {
503                write!(
504                    f,
505                    "field number '{}' conflicts with reserved range '{} to {}'",
506                    number,
507                    range.start,
508                    range.end - 1
509                )
510            }
511            DescriptorErrorKind::FieldNumberInExtensionRange { number, range, .. } => {
512                write!(
513                    f,
514                    "field number '{}' conflicts with extension range '{} to {}'",
515                    number,
516                    range.start,
517                    range.end - 1
518                )
519            }
520            DescriptorErrorKind::ExtensionNumberOutOfRange {
521                number, message, ..
522            } => {
523                write!(
524                    f,
525                    "message '{message}' does not define '{number}' as an extension number"
526                )
527            }
528            DescriptorErrorKind::NameNotFound { name, .. } => {
529                write!(f, "name '{name}' is not defined")
530            }
531            DescriptorErrorKind::NameShadowed {
532                name,
533                shadowed_name,
534                ..
535            } => {
536                write!(
537                    f,
538                    "'{name}' resolves to '{shadowed_name}', which is not defined",
539                )
540            }
541            DescriptorErrorKind::InvalidType { name, expected, .. } => {
542                write!(f, "'{name}' is not {expected}")
543            }
544            DescriptorErrorKind::InvalidFieldDefault { value, kind, .. } => {
545                write!(f, "invalid default value '{value}' for type '{kind}'")
546            }
547            DescriptorErrorKind::EmptyEnum { .. } => {
548                write!(f, "enums must have at least one value")
549            }
550            DescriptorErrorKind::InvalidProto3EnumDefault { .. } => {
551                write!(f, "the first value for proto3 enums must be 0")
552            }
553            DescriptorErrorKind::DuplicateEnumNumber { number, .. } => {
554                write!(f, "enum number '{number}' has already been used")
555            }
556            DescriptorErrorKind::EnumNumberInReservedRange { number, range, .. } => {
557                write!(
558                    f,
559                    "enum number '{}' conflicts with reserved range '{} to {}'",
560                    number,
561                    range.start(),
562                    range.end()
563                )
564            }
565            DescriptorErrorKind::OptionNotFound { name, .. } => {
566                write!(f, "option field '{name}' is not defined")
567            }
568            DescriptorErrorKind::InvalidOptionType {
569                name,
570                ty,
571                value,
572                is_last,
573                ..
574            } => {
575                if *is_last {
576                    write!(
577                        f,
578                        "expected a value of type '{ty}' for option '{name}', but found '{value}'"
579                    )
580                } else {
581                    write!(
582                        f,
583                        "cannot set field for option '{name}' value of type '{ty}'"
584                    )
585                }
586            }
587            DescriptorErrorKind::InvalidOptionExtendee {
588                name,
589                expected_extendee,
590                actual_extendee,
591                ..
592            } => {
593                write!(
594                    f,
595                    "expected an extension to type '{expected_extendee}', but '{name}' extends '{actual_extendee}'"
596                )
597            }
598            #[cfg(feature = "text-format")]
599            DescriptorErrorKind::InvalidMessageOption { name, ty, .. } => {
600                write!(f, "invalid value of type '{ty}' for option '{name}'")
601            }
602            DescriptorErrorKind::DuplicateOption { name, .. } => {
603                write!(f, "option field '{name}' has already been set")
604            }
605            DescriptorErrorKind::DecodeFileDescriptorSet { .. } => {
606                write!(f, "failed to decode file descriptor set")
607            }
608        }
609    }
610}
611
612#[cfg(feature = "miette")]
613#[cfg_attr(docsrs, doc(cfg(feature = "miette")))]
614impl miette::Diagnostic for DescriptorErrorKind {
615    fn help<'a>(&'a self) -> Option<Box<dyn fmt::Display + 'a>> {
616        use crate::descriptor::{RESERVED_MESSAGE_FIELD_NUMBERS, VALID_MESSAGE_FIELD_NUMBERS};
617
618        match self {
619            DescriptorErrorKind::MissingRequiredField { .. } => None,
620            DescriptorErrorKind::UnknownSyntax { .. } => {
621                Some(Box::new("valid values are 'proto2' and 'proto3'"))
622            }
623            DescriptorErrorKind::DuplicateFileName { .. } => None,
624            DescriptorErrorKind::FileNotFound { .. } => None,
625            DescriptorErrorKind::InvalidImportIndex => None,
626            DescriptorErrorKind::InvalidOneofIndex => None,
627            DescriptorErrorKind::DuplicateName { .. } => None,
628            DescriptorErrorKind::DuplicateFieldNumber { .. } => None,
629            DescriptorErrorKind::InvalidFieldNumber { number, .. } => {
630                if !VALID_MESSAGE_FIELD_NUMBERS.contains(number) {
631                    Some(Box::new(format!(
632                        "field numbers must be between {} and {}",
633                        VALID_MESSAGE_FIELD_NUMBERS.start,
634                        VALID_MESSAGE_FIELD_NUMBERS.end - 1
635                    )))
636                } else if RESERVED_MESSAGE_FIELD_NUMBERS.contains(number) {
637                    Some(Box::new(format!(
638                        "field numbers {} to {} are reserved",
639                        RESERVED_MESSAGE_FIELD_NUMBERS.start,
640                        RESERVED_MESSAGE_FIELD_NUMBERS.end - 1
641                    )))
642                } else {
643                    None
644                }
645            }
646            DescriptorErrorKind::FieldNumberInReservedRange { .. } => None,
647            DescriptorErrorKind::FieldNumberInExtensionRange { .. } => None,
648            DescriptorErrorKind::DuplicateFieldJsonName { .. } => None,
649            DescriptorErrorKind::DuplicateFieldCamelCaseName { .. } => None,
650            DescriptorErrorKind::NameNotFound { help, .. }
651            | DescriptorErrorKind::NameShadowed { help, .. } => help
652                .as_ref()
653                .map(|h| -> Box<dyn fmt::Display> { Box::new(h.clone()) }),
654            DescriptorErrorKind::InvalidType { .. } => None,
655            DescriptorErrorKind::InvalidFieldDefault { .. } => None,
656            DescriptorErrorKind::EmptyEnum { .. } => None,
657            DescriptorErrorKind::InvalidProto3EnumDefault { .. } => None,
658            DescriptorErrorKind::DuplicateEnumNumber { .. } => Some(Box::new(
659                "set the 'allow_alias' option allow re-using enum numbers",
660            )),
661            DescriptorErrorKind::EnumNumberInReservedRange { .. } => None,
662            DescriptorErrorKind::OptionNotFound { .. } => None,
663            DescriptorErrorKind::InvalidOptionType { .. } => None,
664            DescriptorErrorKind::InvalidOptionExtendee { .. } => None,
665            #[cfg(feature = "text-format")]
666            DescriptorErrorKind::InvalidMessageOption { .. } => None,
667            DescriptorErrorKind::DuplicateOption { .. } => None,
668            DescriptorErrorKind::DecodeFileDescriptorSet { .. } => None,
669            DescriptorErrorKind::ExtensionNumberOutOfRange { .. } => None,
670        }
671    }
672
673    fn labels(&self) -> Option<Box<dyn Iterator<Item = miette::LabeledSpan> + '_>> {
674        let mut spans = Vec::new();
675        match self {
676            DescriptorErrorKind::MissingRequiredField { label } => spans.extend(label.to_span()),
677            DescriptorErrorKind::UnknownSyntax { found: defined, .. } => {
678                spans.extend(defined.to_span());
679            }
680            DescriptorErrorKind::DuplicateFileName { .. } => {}
681            DescriptorErrorKind::FileNotFound { found, .. } => {
682                spans.extend(found.to_span());
683            }
684            DescriptorErrorKind::InvalidImportIndex => {}
685            DescriptorErrorKind::InvalidOneofIndex => {}
686            DescriptorErrorKind::DuplicateName { first, second, .. } => {
687                spans.extend(first.to_span());
688                spans.extend(second.to_span());
689            }
690            DescriptorErrorKind::DuplicateFieldNumber { first, second, .. } => {
691                spans.extend(first.to_span());
692                spans.extend(second.to_span());
693            }
694            DescriptorErrorKind::DuplicateFieldJsonName { first, second, .. } => {
695                spans.extend(first.to_span());
696                spans.extend(second.to_span());
697            }
698            DescriptorErrorKind::DuplicateFieldCamelCaseName { first, second, .. } => {
699                spans.extend(first.to_span());
700                spans.extend(second.to_span());
701            }
702            DescriptorErrorKind::NameNotFound { found, .. }
703            | DescriptorErrorKind::NameShadowed { found, .. } => {
704                spans.extend(found.to_span());
705            }
706            DescriptorErrorKind::InvalidFieldNumber { found, .. } => {
707                spans.extend(found.to_span());
708            }
709            DescriptorErrorKind::FieldNumberInReservedRange { defined, found, .. } => {
710                spans.extend(defined.to_span());
711                spans.extend(found.to_span());
712            }
713            DescriptorErrorKind::FieldNumberInExtensionRange { defined, found, .. } => {
714                spans.extend(defined.to_span());
715                spans.extend(found.to_span());
716            }
717            DescriptorErrorKind::ExtensionNumberOutOfRange { found, .. } => {
718                spans.extend(found.to_span());
719            }
720            DescriptorErrorKind::InvalidType { found, defined, .. } => {
721                spans.extend(found.to_span());
722                spans.extend(defined.to_span());
723            }
724            DescriptorErrorKind::InvalidFieldDefault { found, .. } => {
725                spans.extend(found.to_span());
726            }
727            DescriptorErrorKind::EmptyEnum { found } => {
728                spans.extend(found.to_span());
729            }
730            DescriptorErrorKind::InvalidProto3EnumDefault { found, .. } => {
731                spans.extend(found.to_span());
732            }
733            DescriptorErrorKind::DuplicateEnumNumber { first, second, .. } => {
734                spans.extend(first.to_span());
735                spans.extend(second.to_span());
736            }
737            DescriptorErrorKind::EnumNumberInReservedRange { defined, found, .. } => {
738                spans.extend(found.to_span());
739                spans.extend(defined.to_span());
740            }
741            DescriptorErrorKind::OptionNotFound { found, .. } => {
742                spans.extend(found.to_span());
743            }
744            DescriptorErrorKind::InvalidOptionType { found, .. } => {
745                spans.extend(found.to_span());
746            }
747            DescriptorErrorKind::InvalidOptionExtendee { found, .. } => {
748                spans.extend(found.to_span());
749            }
750            #[cfg(feature = "text-format")]
751            DescriptorErrorKind::InvalidMessageOption { found, .. } => {
752                spans.extend(found.to_span());
753            }
754            DescriptorErrorKind::DuplicateOption { found, .. } => {
755                spans.extend(found.to_span());
756            }
757            DescriptorErrorKind::DecodeFileDescriptorSet { .. } => {}
758        }
759        if spans.is_empty() {
760            None
761        } else {
762            Some(Box::new(spans.into_iter()))
763        }
764    }
765
766    fn diagnostic_source(&self) -> Option<&dyn miette::Diagnostic> {
767        match self {
768            #[cfg(feature = "text-format")]
769            DescriptorErrorKind::InvalidMessageOption { err, .. } => Some(err),
770            _ => None,
771        }
772    }
773}
774
775impl Label {
776    pub fn new(
777        files: &[FileDescriptorInner],
778        #[cfg_attr(not(feature = "miette"), allow(unused_variables))] message: impl ToString,
779        file: FileIndex,
780        path: Box<[i32]>,
781    ) -> Self {
782        let file = &files[file as usize].raw;
783
784        let span = file
785            .source_code_info
786            .as_ref()
787            .and_then(|s| s.location.iter().find(|l| *l.path == *path))
788            .and_then(|l| match *l.span {
789                [start_line, start_col, end_col] => {
790                    Some([start_line, start_col, start_line, end_col])
791                }
792                [start_line, start_col, end_line, end_col] => {
793                    Some([start_line, start_col, end_line, end_col])
794                }
795                _ => None,
796            });
797
798        Label {
799            file: file.name().to_owned(),
800            span,
801            path,
802            #[cfg(feature = "miette")]
803            message: message.to_string(),
804            #[cfg(feature = "miette")]
805            resolved: None,
806        }
807    }
808
809    #[cfg(feature = "miette")]
810    pub fn resolve_span(&mut self, file: &str, source: &str) {
811        if file == self.file {
812            if let Some([start_line, start_col, end_line, end_col]) = self.span {
813                let start = miette::SourceOffset::from_location(
814                    source,
815                    start_line.saturating_add(1) as _,
816                    start_col.saturating_add(1) as _,
817                )
818                .offset();
819                let end = miette::SourceOffset::from_location(
820                    source,
821                    end_line.saturating_add(1) as _,
822                    end_col.saturating_add(1) as _,
823                )
824                .offset();
825                self.resolved = Some(miette::SourceSpan::from(start..end));
826            }
827        }
828    }
829
830    #[cfg(feature = "miette")]
831    fn to_span(&self) -> Option<miette::LabeledSpan> {
832        match self.resolved {
833            Some(span) if !span.is_empty() => Some(miette::LabeledSpan::new_with_span(
834                Some(self.message.clone()),
835                span,
836            )),
837            _ => None,
838        }
839    }
840}