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!(
458                    f,
459                    "a different file named '{}' has already been added",
460                    name
461                )
462            }
463            DescriptorErrorKind::FileNotFound { name, .. } => {
464                write!(f, "imported file '{}' has not been added", name)
465            }
466            DescriptorErrorKind::InvalidImportIndex => {
467                write!(f, "invalid import index")
468            }
469            DescriptorErrorKind::InvalidOneofIndex => {
470                write!(f, "invalid oneof index")
471            }
472            DescriptorErrorKind::DuplicateName {
473                name,
474                first,
475                second,
476            } => {
477                if first.file == second.file {
478                    write!(f, "name '{}' is defined twice", name)
479                } else {
480                    write!(
481                        f,
482                        "name '{}' is already defined in file '{}'",
483                        name, first.file
484                    )
485                }
486            }
487            DescriptorErrorKind::DuplicateFieldNumber { number, .. } => {
488                write!(f, "field number '{}' is already used", number)
489            }
490            DescriptorErrorKind::DuplicateFieldJsonName { name, .. } => {
491                write!(f, "a field with JSON name '{}' is already defined", name)
492            }
493            DescriptorErrorKind::DuplicateFieldCamelCaseName {
494                first_name,
495                second_name,
496                ..
497            } => {
498                write!(
499                    f,
500                    "camel-case name of field '{first_name}' conflicts with field '{second_name}'"
501                )
502            }
503            DescriptorErrorKind::InvalidFieldNumber { number, .. } => {
504                write!(f, "invalid field number '{}'", number)
505            }
506            DescriptorErrorKind::FieldNumberInReservedRange { number, range, .. } => {
507                write!(
508                    f,
509                    "field number '{}' conflicts with reserved range '{} to {}'",
510                    number,
511                    range.start,
512                    range.end - 1
513                )
514            }
515            DescriptorErrorKind::FieldNumberInExtensionRange { number, range, .. } => {
516                write!(
517                    f,
518                    "field number '{}' conflicts with extension range '{} to {}'",
519                    number,
520                    range.start,
521                    range.end - 1
522                )
523            }
524            DescriptorErrorKind::ExtensionNumberOutOfRange {
525                number, message, ..
526            } => {
527                write!(
528                    f,
529                    "message '{}' does not define '{}' as an extension number",
530                    message, number
531                )
532            }
533            DescriptorErrorKind::NameNotFound { name, .. } => {
534                write!(f, "name '{}' is not defined", name)
535            }
536            DescriptorErrorKind::NameShadowed {
537                name,
538                shadowed_name,
539                ..
540            } => {
541                write!(
542                    f,
543                    "'{name}' resolves to '{shadowed_name}', which is not defined",
544                )
545            }
546            DescriptorErrorKind::InvalidType { name, expected, .. } => {
547                write!(f, "'{}' is not {}", name, expected)
548            }
549            DescriptorErrorKind::InvalidFieldDefault { value, kind, .. } => {
550                write!(f, "invalid default value '{}' for type '{}'", value, kind)
551            }
552            DescriptorErrorKind::EmptyEnum { .. } => {
553                write!(f, "enums must have at least one value")
554            }
555            DescriptorErrorKind::InvalidProto3EnumDefault { .. } => {
556                write!(f, "the first value for proto3 enums must be 0")
557            }
558            DescriptorErrorKind::DuplicateEnumNumber { number, .. } => {
559                write!(f, "enum number '{}' has already been used", number)
560            }
561            DescriptorErrorKind::EnumNumberInReservedRange { number, range, .. } => {
562                write!(
563                    f,
564                    "enum number '{}' conflicts with reserved range '{} to {}'",
565                    number,
566                    range.start(),
567                    range.end()
568                )
569            }
570            DescriptorErrorKind::OptionNotFound { name, .. } => {
571                write!(f, "option field '{}' is not defined", name)
572            }
573            DescriptorErrorKind::InvalidOptionType {
574                name,
575                ty,
576                value,
577                is_last,
578                ..
579            } => {
580                if *is_last {
581                    write!(
582                        f,
583                        "expected a value of type '{}' for option '{}', but found '{}'",
584                        ty, name, value
585                    )
586                } else {
587                    write!(
588                        f,
589                        "cannot set field for option '{}' value of type '{}'",
590                        name, ty
591                    )
592                }
593            }
594            DescriptorErrorKind::InvalidOptionExtendee {
595                name,
596                expected_extendee,
597                actual_extendee,
598                ..
599            } => {
600                write!(
601                    f,
602                    "expected an extension to type '{}', but '{}' extends '{}'",
603                    expected_extendee, name, actual_extendee
604                )
605            }
606            #[cfg(feature = "text-format")]
607            DescriptorErrorKind::InvalidMessageOption { name, ty, .. } => {
608                write!(f, "invalid value of type '{}' for option '{}'", ty, name)
609            }
610            DescriptorErrorKind::DuplicateOption { name, .. } => {
611                write!(f, "option field '{}' has already been set", name)
612            }
613            DescriptorErrorKind::DecodeFileDescriptorSet { .. } => {
614                write!(f, "failed to decode file descriptor set")
615            }
616        }
617    }
618}
619
620#[cfg(feature = "miette")]
621#[cfg_attr(docsrs, doc(cfg(feature = "miette")))]
622impl miette::Diagnostic for DescriptorErrorKind {
623    fn help<'a>(&'a self) -> Option<Box<dyn fmt::Display + 'a>> {
624        use crate::descriptor::{RESERVED_MESSAGE_FIELD_NUMBERS, VALID_MESSAGE_FIELD_NUMBERS};
625
626        match self {
627            DescriptorErrorKind::MissingRequiredField { .. } => None,
628            DescriptorErrorKind::UnknownSyntax { .. } => {
629                Some(Box::new("valid values are 'proto2' and 'proto3'"))
630            }
631            DescriptorErrorKind::DuplicateFileName { .. } => None,
632            DescriptorErrorKind::FileNotFound { .. } => None,
633            DescriptorErrorKind::InvalidImportIndex => None,
634            DescriptorErrorKind::InvalidOneofIndex => None,
635            DescriptorErrorKind::DuplicateName { .. } => None,
636            DescriptorErrorKind::DuplicateFieldNumber { .. } => None,
637            DescriptorErrorKind::InvalidFieldNumber { number, .. } => {
638                if !VALID_MESSAGE_FIELD_NUMBERS.contains(number) {
639                    Some(Box::new(format!(
640                        "field numbers must be between {} and {}",
641                        VALID_MESSAGE_FIELD_NUMBERS.start,
642                        VALID_MESSAGE_FIELD_NUMBERS.end - 1
643                    )))
644                } else if RESERVED_MESSAGE_FIELD_NUMBERS.contains(number) {
645                    Some(Box::new(format!(
646                        "field numbers {} to {} are reserved",
647                        RESERVED_MESSAGE_FIELD_NUMBERS.start,
648                        RESERVED_MESSAGE_FIELD_NUMBERS.end - 1
649                    )))
650                } else {
651                    None
652                }
653            }
654            DescriptorErrorKind::FieldNumberInReservedRange { .. } => None,
655            DescriptorErrorKind::FieldNumberInExtensionRange { .. } => None,
656            DescriptorErrorKind::DuplicateFieldJsonName { .. } => None,
657            DescriptorErrorKind::DuplicateFieldCamelCaseName { .. } => None,
658            DescriptorErrorKind::NameNotFound { help, .. }
659            | DescriptorErrorKind::NameShadowed { help, .. } => help
660                .as_ref()
661                .map(|h| -> Box<dyn fmt::Display> { Box::new(h.clone()) }),
662            DescriptorErrorKind::InvalidType { .. } => None,
663            DescriptorErrorKind::InvalidFieldDefault { .. } => None,
664            DescriptorErrorKind::EmptyEnum { .. } => None,
665            DescriptorErrorKind::InvalidProto3EnumDefault { .. } => None,
666            DescriptorErrorKind::DuplicateEnumNumber { .. } => Some(Box::new(
667                "set the 'allow_alias' option allow re-using enum numbers",
668            )),
669            DescriptorErrorKind::EnumNumberInReservedRange { .. } => None,
670            DescriptorErrorKind::OptionNotFound { .. } => None,
671            DescriptorErrorKind::InvalidOptionType { .. } => None,
672            DescriptorErrorKind::InvalidOptionExtendee { .. } => None,
673            #[cfg(feature = "text-format")]
674            DescriptorErrorKind::InvalidMessageOption { .. } => None,
675            DescriptorErrorKind::DuplicateOption { .. } => None,
676            DescriptorErrorKind::DecodeFileDescriptorSet { .. } => None,
677            DescriptorErrorKind::ExtensionNumberOutOfRange { .. } => None,
678        }
679    }
680
681    fn labels(&self) -> Option<Box<dyn Iterator<Item = miette::LabeledSpan> + '_>> {
682        let mut spans = Vec::new();
683        match self {
684            DescriptorErrorKind::MissingRequiredField { label } => spans.extend(label.to_span()),
685            DescriptorErrorKind::UnknownSyntax { found: defined, .. } => {
686                spans.extend(defined.to_span());
687            }
688            DescriptorErrorKind::DuplicateFileName { .. } => {}
689            DescriptorErrorKind::FileNotFound { found, .. } => {
690                spans.extend(found.to_span());
691            }
692            DescriptorErrorKind::InvalidImportIndex => {}
693            DescriptorErrorKind::InvalidOneofIndex => {}
694            DescriptorErrorKind::DuplicateName { first, second, .. } => {
695                spans.extend(first.to_span());
696                spans.extend(second.to_span());
697            }
698            DescriptorErrorKind::DuplicateFieldNumber { first, second, .. } => {
699                spans.extend(first.to_span());
700                spans.extend(second.to_span());
701            }
702            DescriptorErrorKind::DuplicateFieldJsonName { first, second, .. } => {
703                spans.extend(first.to_span());
704                spans.extend(second.to_span());
705            }
706            DescriptorErrorKind::DuplicateFieldCamelCaseName { first, second, .. } => {
707                spans.extend(first.to_span());
708                spans.extend(second.to_span());
709            }
710            DescriptorErrorKind::NameNotFound { found, .. }
711            | DescriptorErrorKind::NameShadowed { found, .. } => {
712                spans.extend(found.to_span());
713            }
714            DescriptorErrorKind::InvalidFieldNumber { found, .. } => {
715                spans.extend(found.to_span());
716            }
717            DescriptorErrorKind::FieldNumberInReservedRange { defined, found, .. } => {
718                spans.extend(defined.to_span());
719                spans.extend(found.to_span());
720            }
721            DescriptorErrorKind::FieldNumberInExtensionRange { defined, found, .. } => {
722                spans.extend(defined.to_span());
723                spans.extend(found.to_span());
724            }
725            DescriptorErrorKind::ExtensionNumberOutOfRange { found, .. } => {
726                spans.extend(found.to_span());
727            }
728            DescriptorErrorKind::InvalidType { found, defined, .. } => {
729                spans.extend(found.to_span());
730                spans.extend(defined.to_span());
731            }
732            DescriptorErrorKind::InvalidFieldDefault { found, .. } => {
733                spans.extend(found.to_span());
734            }
735            DescriptorErrorKind::EmptyEnum { found } => {
736                spans.extend(found.to_span());
737            }
738            DescriptorErrorKind::InvalidProto3EnumDefault { found, .. } => {
739                spans.extend(found.to_span());
740            }
741            DescriptorErrorKind::DuplicateEnumNumber { first, second, .. } => {
742                spans.extend(first.to_span());
743                spans.extend(second.to_span());
744            }
745            DescriptorErrorKind::EnumNumberInReservedRange { defined, found, .. } => {
746                spans.extend(found.to_span());
747                spans.extend(defined.to_span());
748            }
749            DescriptorErrorKind::OptionNotFound { found, .. } => {
750                spans.extend(found.to_span());
751            }
752            DescriptorErrorKind::InvalidOptionType { found, .. } => {
753                spans.extend(found.to_span());
754            }
755            DescriptorErrorKind::InvalidOptionExtendee { found, .. } => {
756                spans.extend(found.to_span());
757            }
758            #[cfg(feature = "text-format")]
759            DescriptorErrorKind::InvalidMessageOption { found, .. } => {
760                spans.extend(found.to_span());
761            }
762            DescriptorErrorKind::DuplicateOption { found, .. } => {
763                spans.extend(found.to_span());
764            }
765            DescriptorErrorKind::DecodeFileDescriptorSet { .. } => {}
766        }
767        if spans.is_empty() {
768            None
769        } else {
770            Some(Box::new(spans.into_iter()))
771        }
772    }
773
774    fn diagnostic_source(&self) -> Option<&dyn miette::Diagnostic> {
775        match self {
776            #[cfg(feature = "text-format")]
777            DescriptorErrorKind::InvalidMessageOption { err, .. } => Some(err),
778            _ => None,
779        }
780    }
781}
782
783impl Label {
784    pub fn new(
785        files: &[FileDescriptorInner],
786        #[cfg_attr(not(feature = "miette"), allow(unused_variables))] message: impl ToString,
787        file: FileIndex,
788        path: Box<[i32]>,
789    ) -> Self {
790        let file = &files[file as usize].raw;
791
792        let span = file
793            .source_code_info
794            .as_ref()
795            .and_then(|s| s.location.iter().find(|l| *l.path == *path))
796            .and_then(|l| match *l.span {
797                [start_line, start_col, end_col] => {
798                    Some([start_line, start_col, start_line, end_col])
799                }
800                [start_line, start_col, end_line, end_col] => {
801                    Some([start_line, start_col, end_line, end_col])
802                }
803                _ => None,
804            });
805
806        Label {
807            file: file.name().to_owned(),
808            span,
809            path,
810            #[cfg(feature = "miette")]
811            message: message.to_string(),
812            #[cfg(feature = "miette")]
813            resolved: None,
814        }
815    }
816
817    #[cfg(feature = "miette")]
818    pub fn resolve_span(&mut self, file: &str, source: &str) {
819        if file == self.file {
820            if let Some([start_line, start_col, end_line, end_col]) = self.span {
821                let start = miette::SourceOffset::from_location(
822                    source,
823                    start_line.saturating_add(1) as _,
824                    start_col.saturating_add(1) as _,
825                )
826                .offset();
827                let end = miette::SourceOffset::from_location(
828                    source,
829                    end_line.saturating_add(1) as _,
830                    end_col.saturating_add(1) as _,
831                )
832                .offset();
833                self.resolved = Some(miette::SourceSpan::from(start..end));
834            }
835        }
836    }
837
838    #[cfg(feature = "miette")]
839    fn to_span(&self) -> Option<miette::LabeledSpan> {
840        match self.resolved {
841            Some(span) if !span.is_empty() => Some(miette::LabeledSpan::new_with_span(
842                Some(self.message.clone()),
843                span,
844            )),
845            _ => None,
846        }
847    }
848}