1#![cfg_attr(not(feature = "error-context"), allow(dead_code))]
4#![cfg_attr(not(feature = "error-context"), allow(unused_imports))]
5#![cfg_attr(not(feature = "error-context"), allow(unused_variables))]
6#![cfg_attr(not(feature = "error-context"), allow(unused_mut))]
7#![cfg_attr(not(feature = "error-context"), allow(clippy::let_and_return))]
8
9use std::{
11 borrow::Cow,
12 convert::From,
13 error,
14 fmt::{self, Debug, Display, Formatter},
15 io,
16 result::Result as StdResult,
17};
18
19use crate::builder::StyledStr;
21use crate::builder::Styles;
22use crate::output::fmt::Colorizer;
23use crate::output::fmt::Stream;
24use crate::parser::features::suggestions;
25use crate::util::FlatMap;
26use crate::util::{color::ColorChoice, SUCCESS_CODE, USAGE_CODE};
27use crate::Command;
28
29#[cfg(feature = "error-context")]
30mod context;
31mod format;
32mod kind;
33
34pub use format::ErrorFormatter;
35pub use format::KindFormatter;
36pub use kind::ErrorKind;
37
38#[cfg(feature = "error-context")]
39pub use context::ContextKind;
40#[cfg(feature = "error-context")]
41pub use context::ContextValue;
42#[cfg(feature = "error-context")]
43pub use format::RichFormatter;
44
45#[cfg(not(feature = "error-context"))]
46pub use KindFormatter as DefaultFormatter;
47#[cfg(feature = "error-context")]
48pub use RichFormatter as DefaultFormatter;
49
50pub type Result<T, E = Error> = StdResult<T, E>;
54
55pub struct Error<F: ErrorFormatter = DefaultFormatter> {
61 inner: Box<ErrorInner>,
62 phantom: std::marker::PhantomData<F>,
63}
64
65#[derive(Debug)]
66struct ErrorInner {
67 kind: ErrorKind,
68 #[cfg(feature = "error-context")]
69 context: FlatMap<ContextKind, ContextValue>,
70 message: Option<Message>,
71 source: Option<Box<dyn error::Error + Send + Sync>>,
72 help_flag: Option<Cow<'static, str>>,
73 styles: Styles,
74 color_when: ColorChoice,
75 color_help_when: ColorChoice,
76 backtrace: Option<Backtrace>,
77}
78
79impl<F: ErrorFormatter> Error<F> {
80 pub fn raw(kind: ErrorKind, message: impl Display) -> Self {
89 Self::new(kind).set_message(message.to_string())
90 }
91
92 #[must_use]
94 pub fn format(mut self, cmd: &mut Command) -> Self {
95 cmd._build_self(false);
96 let usage = cmd.render_usage_();
97 if let Some(message) = self.inner.message.as_mut() {
98 message.format(cmd, usage);
99 }
100 self.with_cmd(cmd)
101 }
102
103 pub fn new(kind: ErrorKind) -> Self {
129 Self {
130 inner: Box::new(ErrorInner {
131 kind,
132 #[cfg(feature = "error-context")]
133 context: FlatMap::new(),
134 message: None,
135 source: None,
136 help_flag: None,
137 styles: Styles::plain(),
138 color_when: ColorChoice::Never,
139 color_help_when: ColorChoice::Never,
140 backtrace: Backtrace::new(),
141 }),
142 phantom: Default::default(),
143 }
144 }
145
146 pub fn with_cmd(self, cmd: &Command) -> Self {
150 self.set_styles(cmd.get_styles().clone())
151 .set_color(cmd.get_color())
152 .set_colored_help(cmd.color_help())
153 .set_help_flag(format::get_help_flag(cmd))
154 }
155
156 pub fn apply<EF: ErrorFormatter>(self) -> Error<EF> {
173 Error {
174 inner: self.inner,
175 phantom: Default::default(),
176 }
177 }
178
179 pub fn kind(&self) -> ErrorKind {
181 self.inner.kind
182 }
183
184 #[cfg(feature = "error-context")]
186 pub fn context(&self) -> impl Iterator<Item = (ContextKind, &ContextValue)> {
187 self.inner.context.iter().map(|(k, v)| (*k, v))
188 }
189
190 #[inline(never)]
192 #[cfg(feature = "error-context")]
193 pub fn get(&self, kind: ContextKind) -> Option<&ContextValue> {
194 self.inner.context.get(&kind)
195 }
196
197 #[inline(never)]
201 #[cfg(feature = "error-context")]
202 pub fn insert(&mut self, kind: ContextKind, value: ContextValue) -> Option<ContextValue> {
203 self.inner.context.insert(kind, value)
204 }
205
206 #[inline(never)]
211 #[cfg(feature = "error-context")]
212 pub fn remove(&mut self, kind: ContextKind) -> Option<ContextValue> {
213 self.inner.context.remove(&kind)
214 }
215
216 #[inline]
218 pub fn use_stderr(&self) -> bool {
219 self.stream() == Stream::Stderr
220 }
221
222 pub(crate) fn stream(&self) -> Stream {
223 match self.kind() {
224 ErrorKind::DisplayHelp | ErrorKind::DisplayVersion => Stream::Stdout,
225 _ => Stream::Stderr,
226 }
227 }
228
229 pub fn exit_code(&self) -> i32 {
234 if self.use_stderr() {
235 USAGE_CODE
236 } else {
237 SUCCESS_CODE
238 }
239 }
240
241 pub fn exit(&self) -> ! {
246 let _ = self.print();
248 std::process::exit(self.exit_code());
249 }
250
251 pub fn print(&self) -> io::Result<()> {
269 let style = self.formatted();
270 let color_when = if matches!(
271 self.kind(),
272 ErrorKind::DisplayHelp | ErrorKind::DisplayHelpOnMissingArgumentOrSubcommand,
273 ) {
274 self.inner.color_help_when
275 } else {
276 self.inner.color_when
277 };
278 let c = Colorizer::new(self.stream(), color_when).with_content(style.into_owned());
279 c.print()
280 }
281
282 pub fn render(&self) -> StyledStr {
301 self.formatted().into_owned()
302 }
303
304 #[inline(never)]
305 fn for_app(kind: ErrorKind, cmd: &Command, styled: StyledStr) -> Self {
306 Self::new(kind).set_message(styled).with_cmd(cmd)
307 }
308
309 pub(crate) fn set_message(mut self, message: impl Into<Message>) -> Self {
310 self.inner.message = Some(message.into());
311 self
312 }
313
314 pub(crate) fn set_source(mut self, source: Box<dyn error::Error + Send + Sync>) -> Self {
315 self.inner.source = Some(source);
316 self
317 }
318
319 pub(crate) fn set_styles(mut self, styles: Styles) -> Self {
320 self.inner.styles = styles;
321 self
322 }
323
324 pub(crate) fn set_color(mut self, color_when: ColorChoice) -> Self {
325 self.inner.color_when = color_when;
326 self
327 }
328
329 pub(crate) fn set_colored_help(mut self, color_help_when: ColorChoice) -> Self {
330 self.inner.color_help_when = color_help_when;
331 self
332 }
333
334 pub(crate) fn set_help_flag(mut self, help_flag: Option<Cow<'static, str>>) -> Self {
335 self.inner.help_flag = help_flag;
336 self
337 }
338
339 #[inline(never)]
341 #[cfg(feature = "error-context")]
342 pub(crate) fn insert_context_unchecked(
343 mut self,
344 kind: ContextKind,
345 value: ContextValue,
346 ) -> Self {
347 self.inner.context.insert_unchecked(kind, value);
348 self
349 }
350
351 #[inline(never)]
353 #[cfg(feature = "error-context")]
354 pub(crate) fn extend_context_unchecked<const N: usize>(
355 mut self,
356 context: [(ContextKind, ContextValue); N],
357 ) -> Self {
358 self.inner.context.extend_unchecked(context);
359 self
360 }
361
362 pub(crate) fn display_help(cmd: &Command, styled: StyledStr) -> Self {
363 Self::for_app(ErrorKind::DisplayHelp, cmd, styled)
364 }
365
366 pub(crate) fn display_help_error(cmd: &Command, styled: StyledStr) -> Self {
367 Self::for_app(
368 ErrorKind::DisplayHelpOnMissingArgumentOrSubcommand,
369 cmd,
370 styled,
371 )
372 }
373
374 pub(crate) fn display_version(cmd: &Command, styled: StyledStr) -> Self {
375 Self::for_app(ErrorKind::DisplayVersion, cmd, styled)
376 }
377
378 pub(crate) fn argument_conflict(
379 cmd: &Command,
380 arg: String,
381 mut others: Vec<String>,
382 usage: Option<StyledStr>,
383 ) -> Self {
384 let mut err = Self::new(ErrorKind::ArgumentConflict).with_cmd(cmd);
385
386 #[cfg(feature = "error-context")]
387 {
388 let others = match others.len() {
389 0 => ContextValue::None,
390 1 => ContextValue::String(others.pop().unwrap()),
391 _ => ContextValue::Strings(others),
392 };
393 err = err.extend_context_unchecked([
394 (ContextKind::InvalidArg, ContextValue::String(arg)),
395 (ContextKind::PriorArg, others),
396 ]);
397 if let Some(usage) = usage {
398 err = err
399 .insert_context_unchecked(ContextKind::Usage, ContextValue::StyledStr(usage));
400 }
401 }
402
403 err
404 }
405
406 pub(crate) fn subcommand_conflict(
407 cmd: &Command,
408 sub: String,
409 mut others: Vec<String>,
410 usage: Option<StyledStr>,
411 ) -> Self {
412 let mut err = Self::new(ErrorKind::ArgumentConflict).with_cmd(cmd);
413
414 #[cfg(feature = "error-context")]
415 {
416 let others = match others.len() {
417 0 => ContextValue::None,
418 1 => ContextValue::String(others.pop().unwrap()),
419 _ => ContextValue::Strings(others),
420 };
421 err = err.extend_context_unchecked([
422 (ContextKind::InvalidSubcommand, ContextValue::String(sub)),
423 (ContextKind::PriorArg, others),
424 ]);
425 if let Some(usage) = usage {
426 err = err
427 .insert_context_unchecked(ContextKind::Usage, ContextValue::StyledStr(usage));
428 }
429 }
430
431 err
432 }
433
434 pub(crate) fn empty_value(cmd: &Command, good_vals: &[String], arg: String) -> Self {
435 Self::invalid_value(cmd, "".to_owned(), good_vals, arg)
436 }
437
438 pub(crate) fn no_equals(cmd: &Command, arg: String, usage: Option<StyledStr>) -> Self {
439 let mut err = Self::new(ErrorKind::NoEquals).with_cmd(cmd);
440
441 #[cfg(feature = "error-context")]
442 {
443 err = err
444 .extend_context_unchecked([(ContextKind::InvalidArg, ContextValue::String(arg))]);
445 if let Some(usage) = usage {
446 err = err
447 .insert_context_unchecked(ContextKind::Usage, ContextValue::StyledStr(usage));
448 }
449 }
450
451 err
452 }
453
454 pub(crate) fn invalid_value(
455 cmd: &Command,
456 bad_val: String,
457 good_vals: &[String],
458 arg: String,
459 ) -> Self {
460 let suggestion = suggestions::did_you_mean(&bad_val, good_vals.iter()).pop();
461 let mut err = Self::new(ErrorKind::InvalidValue).with_cmd(cmd);
462
463 #[cfg(feature = "error-context")]
464 {
465 err = err.extend_context_unchecked([
466 (ContextKind::InvalidArg, ContextValue::String(arg)),
467 (ContextKind::InvalidValue, ContextValue::String(bad_val)),
468 (
469 ContextKind::ValidValue,
470 ContextValue::Strings(good_vals.iter().map(|s| (*s).clone()).collect()),
471 ),
472 ]);
473 if let Some(suggestion) = suggestion {
474 err = err.insert_context_unchecked(
475 ContextKind::SuggestedValue,
476 ContextValue::String(suggestion),
477 );
478 }
479 }
480
481 err
482 }
483
484 pub(crate) fn invalid_subcommand(
485 cmd: &Command,
486 subcmd: String,
487 did_you_mean: Vec<String>,
488 name: String,
489 suggested_trailing_arg: bool,
490 usage: Option<StyledStr>,
491 ) -> Self {
492 use std::fmt::Write as _;
493 let styles = cmd.get_styles();
494 let invalid = &styles.get_invalid();
495 let valid = &styles.get_valid();
496 let mut err = Self::new(ErrorKind::InvalidSubcommand).with_cmd(cmd);
497
498 #[cfg(feature = "error-context")]
499 {
500 let mut suggestions = vec![];
501 if suggested_trailing_arg {
502 let mut styled_suggestion = StyledStr::new();
503 let _ = write!(
504 styled_suggestion,
505 "to pass '{invalid}{subcmd}{invalid:#}' as a value, use '{valid}{name} -- {subcmd}{valid:#}'",
506 );
507 suggestions.push(styled_suggestion);
508 }
509
510 err = err.extend_context_unchecked([
511 (ContextKind::InvalidSubcommand, ContextValue::String(subcmd)),
512 (
513 ContextKind::SuggestedSubcommand,
514 ContextValue::Strings(did_you_mean),
515 ),
516 (
517 ContextKind::Suggested,
518 ContextValue::StyledStrs(suggestions),
519 ),
520 ]);
521 if let Some(usage) = usage {
522 err = err
523 .insert_context_unchecked(ContextKind::Usage, ContextValue::StyledStr(usage));
524 }
525 }
526
527 err
528 }
529
530 pub(crate) fn unrecognized_subcommand(
531 cmd: &Command,
532 subcmd: String,
533 usage: Option<StyledStr>,
534 ) -> Self {
535 let mut err = Self::new(ErrorKind::InvalidSubcommand).with_cmd(cmd);
536
537 #[cfg(feature = "error-context")]
538 {
539 err = err.extend_context_unchecked([(
540 ContextKind::InvalidSubcommand,
541 ContextValue::String(subcmd),
542 )]);
543 if let Some(usage) = usage {
544 err = err
545 .insert_context_unchecked(ContextKind::Usage, ContextValue::StyledStr(usage));
546 }
547 }
548
549 err
550 }
551
552 pub(crate) fn missing_required_argument(
553 cmd: &Command,
554 required: Vec<String>,
555 usage: Option<StyledStr>,
556 ) -> Self {
557 let mut err = Self::new(ErrorKind::MissingRequiredArgument).with_cmd(cmd);
558
559 #[cfg(feature = "error-context")]
560 {
561 err = err.extend_context_unchecked([(
562 ContextKind::InvalidArg,
563 ContextValue::Strings(required),
564 )]);
565 if let Some(usage) = usage {
566 err = err
567 .insert_context_unchecked(ContextKind::Usage, ContextValue::StyledStr(usage));
568 }
569 }
570
571 err
572 }
573
574 pub(crate) fn missing_subcommand(
575 cmd: &Command,
576 parent: String,
577 available: Vec<String>,
578 usage: Option<StyledStr>,
579 ) -> Self {
580 let mut err = Self::new(ErrorKind::MissingSubcommand).with_cmd(cmd);
581
582 #[cfg(feature = "error-context")]
583 {
584 err = err.extend_context_unchecked([
585 (ContextKind::InvalidSubcommand, ContextValue::String(parent)),
586 (
587 ContextKind::ValidSubcommand,
588 ContextValue::Strings(available),
589 ),
590 ]);
591 if let Some(usage) = usage {
592 err = err
593 .insert_context_unchecked(ContextKind::Usage, ContextValue::StyledStr(usage));
594 }
595 }
596
597 err
598 }
599
600 pub(crate) fn invalid_utf8(cmd: &Command, usage: Option<StyledStr>) -> Self {
601 let mut err = Self::new(ErrorKind::InvalidUtf8).with_cmd(cmd);
602
603 #[cfg(feature = "error-context")]
604 {
605 if let Some(usage) = usage {
606 err = err
607 .insert_context_unchecked(ContextKind::Usage, ContextValue::StyledStr(usage));
608 }
609 }
610
611 err
612 }
613
614 pub(crate) fn too_many_values(
615 cmd: &Command,
616 val: String,
617 arg: String,
618 usage: Option<StyledStr>,
619 ) -> Self {
620 let mut err = Self::new(ErrorKind::TooManyValues).with_cmd(cmd);
621
622 #[cfg(feature = "error-context")]
623 {
624 err = err.extend_context_unchecked([
625 (ContextKind::InvalidArg, ContextValue::String(arg)),
626 (ContextKind::InvalidValue, ContextValue::String(val)),
627 ]);
628 if let Some(usage) = usage {
629 err = err
630 .insert_context_unchecked(ContextKind::Usage, ContextValue::StyledStr(usage));
631 }
632 }
633
634 err
635 }
636
637 pub(crate) fn too_few_values(
638 cmd: &Command,
639 arg: String,
640 min_vals: usize,
641 curr_vals: usize,
642 usage: Option<StyledStr>,
643 ) -> Self {
644 let mut err = Self::new(ErrorKind::TooFewValues).with_cmd(cmd);
645
646 #[cfg(feature = "error-context")]
647 {
648 err = err.extend_context_unchecked([
649 (ContextKind::InvalidArg, ContextValue::String(arg)),
650 (
651 ContextKind::MinValues,
652 ContextValue::Number(min_vals as isize),
653 ),
654 (
655 ContextKind::ActualNumValues,
656 ContextValue::Number(curr_vals as isize),
657 ),
658 ]);
659 if let Some(usage) = usage {
660 err = err
661 .insert_context_unchecked(ContextKind::Usage, ContextValue::StyledStr(usage));
662 }
663 }
664
665 err
666 }
667
668 pub(crate) fn value_validation(
669 arg: String,
670 val: String,
671 err: Box<dyn error::Error + Send + Sync>,
672 ) -> Self {
673 let mut err = Self::new(ErrorKind::ValueValidation).set_source(err);
674
675 #[cfg(feature = "error-context")]
676 {
677 err = err.extend_context_unchecked([
678 (ContextKind::InvalidArg, ContextValue::String(arg)),
679 (ContextKind::InvalidValue, ContextValue::String(val)),
680 ]);
681 }
682
683 err
684 }
685
686 pub(crate) fn wrong_number_of_values(
687 cmd: &Command,
688 arg: String,
689 num_vals: usize,
690 curr_vals: usize,
691 usage: Option<StyledStr>,
692 ) -> Self {
693 let mut err = Self::new(ErrorKind::WrongNumberOfValues).with_cmd(cmd);
694
695 #[cfg(feature = "error-context")]
696 {
697 err = err.extend_context_unchecked([
698 (ContextKind::InvalidArg, ContextValue::String(arg)),
699 (
700 ContextKind::ExpectedNumValues,
701 ContextValue::Number(num_vals as isize),
702 ),
703 (
704 ContextKind::ActualNumValues,
705 ContextValue::Number(curr_vals as isize),
706 ),
707 ]);
708 if let Some(usage) = usage {
709 err = err
710 .insert_context_unchecked(ContextKind::Usage, ContextValue::StyledStr(usage));
711 }
712 }
713
714 err
715 }
716
717 pub(crate) fn unknown_argument(
718 cmd: &Command,
719 arg: String,
720 did_you_mean: Option<(String, Option<String>)>,
721 suggested_trailing_arg: bool,
722 usage: Option<StyledStr>,
723 ) -> Self {
724 use std::fmt::Write as _;
725 let styles = cmd.get_styles();
726 let invalid = &styles.get_invalid();
727 let valid = &styles.get_valid();
728 let mut err = Self::new(ErrorKind::UnknownArgument).with_cmd(cmd);
729
730 #[cfg(feature = "error-context")]
731 {
732 let mut suggestions = vec![];
733 if suggested_trailing_arg {
734 let mut styled_suggestion = StyledStr::new();
735 let _ = write!(
736 styled_suggestion,
737 "to pass '{invalid}{arg}{invalid:#}' as a value, use '{valid}-- {arg}{valid:#}'",
738 );
739 suggestions.push(styled_suggestion);
740 }
741
742 err = err
743 .extend_context_unchecked([(ContextKind::InvalidArg, ContextValue::String(arg))]);
744 if let Some(usage) = usage {
745 err = err
746 .insert_context_unchecked(ContextKind::Usage, ContextValue::StyledStr(usage));
747 }
748 match did_you_mean {
749 Some((flag, Some(sub))) => {
750 let mut styled_suggestion = StyledStr::new();
751 let _ = write!(styled_suggestion, "'{valid}{sub} {flag}{valid:#}' exists",);
752 suggestions.push(styled_suggestion);
753 }
754 Some((flag, None)) => {
755 err = err.insert_context_unchecked(
756 ContextKind::SuggestedArg,
757 ContextValue::String(flag),
758 );
759 }
760 None => {}
761 }
762 if !suggestions.is_empty() {
763 err = err.insert_context_unchecked(
764 ContextKind::Suggested,
765 ContextValue::StyledStrs(suggestions),
766 );
767 }
768 }
769
770 err
771 }
772
773 pub(crate) fn unnecessary_double_dash(
774 cmd: &Command,
775 arg: String,
776 usage: Option<StyledStr>,
777 ) -> Self {
778 use std::fmt::Write as _;
779 let styles = cmd.get_styles();
780 let invalid = &styles.get_invalid();
781 let valid = &styles.get_valid();
782 let mut err = Self::new(ErrorKind::UnknownArgument).with_cmd(cmd);
783
784 #[cfg(feature = "error-context")]
785 {
786 let mut styled_suggestion = StyledStr::new();
787 let _ = write!(
788 styled_suggestion,
789 "subcommand '{valid}{arg}{valid:#}' exists; to use it, remove the '{invalid}--{invalid:#}' before it",
790 );
791
792 err = err.extend_context_unchecked([
793 (ContextKind::InvalidArg, ContextValue::String(arg)),
794 (
795 ContextKind::Suggested,
796 ContextValue::StyledStrs(vec![styled_suggestion]),
797 ),
798 ]);
799 if let Some(usage) = usage {
800 err = err
801 .insert_context_unchecked(ContextKind::Usage, ContextValue::StyledStr(usage));
802 }
803 }
804
805 err
806 }
807
808 fn formatted(&self) -> Cow<'_, StyledStr> {
809 if let Some(message) = self.inner.message.as_ref() {
810 message.formatted(&self.inner.styles)
811 } else {
812 let styled = F::format_error(self);
813 Cow::Owned(styled)
814 }
815 }
816}
817
818impl<F: ErrorFormatter> From<io::Error> for Error<F> {
819 fn from(e: io::Error) -> Self {
820 Error::raw(ErrorKind::Io, e)
821 }
822}
823
824impl<F: ErrorFormatter> From<fmt::Error> for Error<F> {
825 fn from(e: fmt::Error) -> Self {
826 Error::raw(ErrorKind::Format, e)
827 }
828}
829
830impl<F: ErrorFormatter> Debug for Error<F> {
831 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
832 self.inner.fmt(f)
833 }
834}
835
836impl<F: ErrorFormatter> error::Error for Error<F> {
837 #[allow(trivial_casts)]
838 fn source(&self) -> Option<&(dyn error::Error + 'static)> {
839 self.inner.source.as_ref().map(|e| e.as_ref() as _)
840 }
841}
842
843impl<F: ErrorFormatter> Display for Error<F> {
844 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
845 ok!(write!(f, "{}", self.formatted()));
847 if let Some(backtrace) = self.inner.backtrace.as_ref() {
848 ok!(writeln!(f));
849 ok!(writeln!(f, "Backtrace:"));
850 ok!(writeln!(f, "{backtrace}"));
851 }
852 Ok(())
853 }
854}
855
856#[derive(Clone, Debug)]
857pub(crate) enum Message {
858 Raw(String),
859 Formatted(StyledStr),
860}
861
862impl Message {
863 fn format(&mut self, cmd: &Command, usage: Option<StyledStr>) {
864 match self {
865 Message::Raw(s) => {
866 let mut message = String::new();
867 std::mem::swap(s, &mut message);
868
869 let styled = format::format_error_message(
870 &message,
871 cmd.get_styles(),
872 Some(cmd),
873 usage.as_ref(),
874 );
875
876 *self = Self::Formatted(styled);
877 }
878 Message::Formatted(_) => {}
879 }
880 }
881
882 fn formatted(&self, styles: &Styles) -> Cow<'_, StyledStr> {
883 match self {
884 Message::Raw(s) => {
885 let styled = format::format_error_message(s, styles, None, None);
886
887 Cow::Owned(styled)
888 }
889 Message::Formatted(s) => Cow::Borrowed(s),
890 }
891 }
892}
893
894impl From<String> for Message {
895 fn from(inner: String) -> Self {
896 Self::Raw(inner)
897 }
898}
899
900impl From<StyledStr> for Message {
901 fn from(inner: StyledStr) -> Self {
902 Self::Formatted(inner)
903 }
904}
905
906#[cfg(feature = "debug")]
907#[derive(Debug)]
908struct Backtrace(backtrace::Backtrace);
909
910#[cfg(feature = "debug")]
911impl Backtrace {
912 fn new() -> Option<Self> {
913 Some(Self(backtrace::Backtrace::new()))
914 }
915}
916
917#[cfg(feature = "debug")]
918impl Display for Backtrace {
919 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
920 write!(f, "{:?}", self.0)
922 }
923}
924
925#[cfg(not(feature = "debug"))]
926#[derive(Debug)]
927struct Backtrace;
928
929#[cfg(not(feature = "debug"))]
930impl Backtrace {
931 fn new() -> Option<Self> {
932 None
933 }
934}
935
936#[cfg(not(feature = "debug"))]
937impl Display for Backtrace {
938 fn fmt(&self, _: &mut Formatter<'_>) -> fmt::Result {
939 Ok(())
940 }
941}
942
943#[test]
944fn check_auto_traits() {
945 static_assertions::assert_impl_all!(Error: Send, Sync, Unpin);
946}