1use std::{
2 fmt,
3 ops::{Range, RangeInclusive},
4};
5
6use crate::descriptor::{FileDescriptorInner, FileIndex};
7
8pub 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 pub fn file(&self) -> Option<&str> {
180 self.first().label().map(|l| l.file.as_str())
181 }
182
183 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 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 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 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}