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)]
199 #[cfg(feature = "error-context")]
200 pub fn insert(&mut self, kind: ContextKind, value: ContextValue) -> Option<ContextValue> {
201 self.inner.context.insert(kind, value)
202 }
203
204 #[inline]
206 pub fn use_stderr(&self) -> bool {
207 self.stream() == Stream::Stderr
208 }
209
210 pub(crate) fn stream(&self) -> Stream {
211 match self.kind() {
212 ErrorKind::DisplayHelp | ErrorKind::DisplayVersion => Stream::Stdout,
213 _ => Stream::Stderr,
214 }
215 }
216
217 pub fn exit_code(&self) -> i32 {
222 if self.use_stderr() {
223 USAGE_CODE
224 } else {
225 SUCCESS_CODE
226 }
227 }
228
229 pub fn exit(&self) -> ! {
234 let _ = self.print();
236 std::process::exit(self.exit_code());
237 }
238
239 pub fn print(&self) -> io::Result<()> {
257 let style = self.formatted();
258 let color_when = if matches!(
259 self.kind(),
260 ErrorKind::DisplayHelp | ErrorKind::DisplayHelpOnMissingArgumentOrSubcommand,
261 ) {
262 self.inner.color_help_when
263 } else {
264 self.inner.color_when
265 };
266 let c = Colorizer::new(self.stream(), color_when).with_content(style.into_owned());
267 c.print()
268 }
269
270 pub fn render(&self) -> StyledStr {
289 self.formatted().into_owned()
290 }
291
292 #[inline(never)]
293 fn for_app(kind: ErrorKind, cmd: &Command, styled: StyledStr) -> Self {
294 Self::new(kind).set_message(styled).with_cmd(cmd)
295 }
296
297 pub(crate) fn set_message(mut self, message: impl Into<Message>) -> Self {
298 self.inner.message = Some(message.into());
299 self
300 }
301
302 pub(crate) fn set_source(mut self, source: Box<dyn error::Error + Send + Sync>) -> Self {
303 self.inner.source = Some(source);
304 self
305 }
306
307 pub(crate) fn set_styles(mut self, styles: Styles) -> Self {
308 self.inner.styles = styles;
309 self
310 }
311
312 pub(crate) fn set_color(mut self, color_when: ColorChoice) -> Self {
313 self.inner.color_when = color_when;
314 self
315 }
316
317 pub(crate) fn set_colored_help(mut self, color_help_when: ColorChoice) -> Self {
318 self.inner.color_help_when = color_help_when;
319 self
320 }
321
322 pub(crate) fn set_help_flag(mut self, help_flag: Option<Cow<'static, str>>) -> Self {
323 self.inner.help_flag = help_flag;
324 self
325 }
326
327 #[inline(never)]
329 #[cfg(feature = "error-context")]
330 pub(crate) fn insert_context_unchecked(
331 mut self,
332 kind: ContextKind,
333 value: ContextValue,
334 ) -> Self {
335 self.inner.context.insert_unchecked(kind, value);
336 self
337 }
338
339 #[inline(never)]
341 #[cfg(feature = "error-context")]
342 pub(crate) fn extend_context_unchecked<const N: usize>(
343 mut self,
344 context: [(ContextKind, ContextValue); N],
345 ) -> Self {
346 self.inner.context.extend_unchecked(context);
347 self
348 }
349
350 pub(crate) fn display_help(cmd: &Command, styled: StyledStr) -> Self {
351 Self::for_app(ErrorKind::DisplayHelp, cmd, styled)
352 }
353
354 pub(crate) fn display_help_error(cmd: &Command, styled: StyledStr) -> Self {
355 Self::for_app(
356 ErrorKind::DisplayHelpOnMissingArgumentOrSubcommand,
357 cmd,
358 styled,
359 )
360 }
361
362 pub(crate) fn display_version(cmd: &Command, styled: StyledStr) -> Self {
363 Self::for_app(ErrorKind::DisplayVersion, cmd, styled)
364 }
365
366 pub(crate) fn argument_conflict(
367 cmd: &Command,
368 arg: String,
369 mut others: Vec<String>,
370 usage: Option<StyledStr>,
371 ) -> Self {
372 let mut err = Self::new(ErrorKind::ArgumentConflict).with_cmd(cmd);
373
374 #[cfg(feature = "error-context")]
375 {
376 let others = match others.len() {
377 0 => ContextValue::None,
378 1 => ContextValue::String(others.pop().unwrap()),
379 _ => ContextValue::Strings(others),
380 };
381 err = err.extend_context_unchecked([
382 (ContextKind::InvalidArg, ContextValue::String(arg)),
383 (ContextKind::PriorArg, others),
384 ]);
385 if let Some(usage) = usage {
386 err = err
387 .insert_context_unchecked(ContextKind::Usage, ContextValue::StyledStr(usage));
388 }
389 }
390
391 err
392 }
393
394 pub(crate) fn subcommand_conflict(
395 cmd: &Command,
396 sub: String,
397 mut others: Vec<String>,
398 usage: Option<StyledStr>,
399 ) -> Self {
400 let mut err = Self::new(ErrorKind::ArgumentConflict).with_cmd(cmd);
401
402 #[cfg(feature = "error-context")]
403 {
404 let others = match others.len() {
405 0 => ContextValue::None,
406 1 => ContextValue::String(others.pop().unwrap()),
407 _ => ContextValue::Strings(others),
408 };
409 err = err.extend_context_unchecked([
410 (ContextKind::InvalidSubcommand, ContextValue::String(sub)),
411 (ContextKind::PriorArg, others),
412 ]);
413 if let Some(usage) = usage {
414 err = err
415 .insert_context_unchecked(ContextKind::Usage, ContextValue::StyledStr(usage));
416 }
417 }
418
419 err
420 }
421
422 pub(crate) fn empty_value(cmd: &Command, good_vals: &[String], arg: String) -> Self {
423 Self::invalid_value(cmd, "".to_owned(), good_vals, arg)
424 }
425
426 pub(crate) fn no_equals(cmd: &Command, arg: String, usage: Option<StyledStr>) -> Self {
427 let mut err = Self::new(ErrorKind::NoEquals).with_cmd(cmd);
428
429 #[cfg(feature = "error-context")]
430 {
431 err = err
432 .extend_context_unchecked([(ContextKind::InvalidArg, ContextValue::String(arg))]);
433 if let Some(usage) = usage {
434 err = err
435 .insert_context_unchecked(ContextKind::Usage, ContextValue::StyledStr(usage));
436 }
437 }
438
439 err
440 }
441
442 pub(crate) fn invalid_value(
443 cmd: &Command,
444 bad_val: String,
445 good_vals: &[String],
446 arg: String,
447 ) -> Self {
448 let suggestion = suggestions::did_you_mean(&bad_val, good_vals.iter()).pop();
449 let mut err = Self::new(ErrorKind::InvalidValue).with_cmd(cmd);
450
451 #[cfg(feature = "error-context")]
452 {
453 err = err.extend_context_unchecked([
454 (ContextKind::InvalidArg, ContextValue::String(arg)),
455 (ContextKind::InvalidValue, ContextValue::String(bad_val)),
456 (
457 ContextKind::ValidValue,
458 ContextValue::Strings(good_vals.iter().map(|s| (*s).clone()).collect()),
459 ),
460 ]);
461 if let Some(suggestion) = suggestion {
462 err = err.insert_context_unchecked(
463 ContextKind::SuggestedValue,
464 ContextValue::String(suggestion),
465 );
466 }
467 }
468
469 err
470 }
471
472 pub(crate) fn invalid_subcommand(
473 cmd: &Command,
474 subcmd: String,
475 did_you_mean: Vec<String>,
476 name: String,
477 suggested_trailing_arg: bool,
478 usage: Option<StyledStr>,
479 ) -> Self {
480 use std::fmt::Write as _;
481 let styles = cmd.get_styles();
482 let invalid = &styles.get_invalid();
483 let valid = &styles.get_valid();
484 let mut err = Self::new(ErrorKind::InvalidSubcommand).with_cmd(cmd);
485
486 #[cfg(feature = "error-context")]
487 {
488 let mut suggestions = vec![];
489 if suggested_trailing_arg {
490 let mut styled_suggestion = StyledStr::new();
491 let _ = write!(
492 styled_suggestion,
493 "to pass '{invalid}{subcmd}{invalid:#}' as a value, use '{valid}{name} -- {subcmd}{valid:#}'",
494 );
495 suggestions.push(styled_suggestion);
496 }
497
498 err = err.extend_context_unchecked([
499 (ContextKind::InvalidSubcommand, ContextValue::String(subcmd)),
500 (
501 ContextKind::SuggestedSubcommand,
502 ContextValue::Strings(did_you_mean),
503 ),
504 (
505 ContextKind::Suggested,
506 ContextValue::StyledStrs(suggestions),
507 ),
508 ]);
509 if let Some(usage) = usage {
510 err = err
511 .insert_context_unchecked(ContextKind::Usage, ContextValue::StyledStr(usage));
512 }
513 }
514
515 err
516 }
517
518 pub(crate) fn unrecognized_subcommand(
519 cmd: &Command,
520 subcmd: String,
521 usage: Option<StyledStr>,
522 ) -> Self {
523 let mut err = Self::new(ErrorKind::InvalidSubcommand).with_cmd(cmd);
524
525 #[cfg(feature = "error-context")]
526 {
527 err = err.extend_context_unchecked([(
528 ContextKind::InvalidSubcommand,
529 ContextValue::String(subcmd),
530 )]);
531 if let Some(usage) = usage {
532 err = err
533 .insert_context_unchecked(ContextKind::Usage, ContextValue::StyledStr(usage));
534 }
535 }
536
537 err
538 }
539
540 pub(crate) fn missing_required_argument(
541 cmd: &Command,
542 required: Vec<String>,
543 usage: Option<StyledStr>,
544 ) -> Self {
545 let mut err = Self::new(ErrorKind::MissingRequiredArgument).with_cmd(cmd);
546
547 #[cfg(feature = "error-context")]
548 {
549 err = err.extend_context_unchecked([(
550 ContextKind::InvalidArg,
551 ContextValue::Strings(required),
552 )]);
553 if let Some(usage) = usage {
554 err = err
555 .insert_context_unchecked(ContextKind::Usage, ContextValue::StyledStr(usage));
556 }
557 }
558
559 err
560 }
561
562 pub(crate) fn missing_subcommand(
563 cmd: &Command,
564 parent: String,
565 available: Vec<String>,
566 usage: Option<StyledStr>,
567 ) -> Self {
568 let mut err = Self::new(ErrorKind::MissingSubcommand).with_cmd(cmd);
569
570 #[cfg(feature = "error-context")]
571 {
572 err = err.extend_context_unchecked([
573 (ContextKind::InvalidSubcommand, ContextValue::String(parent)),
574 (
575 ContextKind::ValidSubcommand,
576 ContextValue::Strings(available),
577 ),
578 ]);
579 if let Some(usage) = usage {
580 err = err
581 .insert_context_unchecked(ContextKind::Usage, ContextValue::StyledStr(usage));
582 }
583 }
584
585 err
586 }
587
588 pub(crate) fn invalid_utf8(cmd: &Command, usage: Option<StyledStr>) -> Self {
589 let mut err = Self::new(ErrorKind::InvalidUtf8).with_cmd(cmd);
590
591 #[cfg(feature = "error-context")]
592 {
593 if let Some(usage) = usage {
594 err = err
595 .insert_context_unchecked(ContextKind::Usage, ContextValue::StyledStr(usage));
596 }
597 }
598
599 err
600 }
601
602 pub(crate) fn too_many_values(
603 cmd: &Command,
604 val: String,
605 arg: String,
606 usage: Option<StyledStr>,
607 ) -> Self {
608 let mut err = Self::new(ErrorKind::TooManyValues).with_cmd(cmd);
609
610 #[cfg(feature = "error-context")]
611 {
612 err = err.extend_context_unchecked([
613 (ContextKind::InvalidArg, ContextValue::String(arg)),
614 (ContextKind::InvalidValue, ContextValue::String(val)),
615 ]);
616 if let Some(usage) = usage {
617 err = err
618 .insert_context_unchecked(ContextKind::Usage, ContextValue::StyledStr(usage));
619 }
620 }
621
622 err
623 }
624
625 pub(crate) fn too_few_values(
626 cmd: &Command,
627 arg: String,
628 min_vals: usize,
629 curr_vals: usize,
630 usage: Option<StyledStr>,
631 ) -> Self {
632 let mut err = Self::new(ErrorKind::TooFewValues).with_cmd(cmd);
633
634 #[cfg(feature = "error-context")]
635 {
636 err = err.extend_context_unchecked([
637 (ContextKind::InvalidArg, ContextValue::String(arg)),
638 (
639 ContextKind::MinValues,
640 ContextValue::Number(min_vals as isize),
641 ),
642 (
643 ContextKind::ActualNumValues,
644 ContextValue::Number(curr_vals as isize),
645 ),
646 ]);
647 if let Some(usage) = usage {
648 err = err
649 .insert_context_unchecked(ContextKind::Usage, ContextValue::StyledStr(usage));
650 }
651 }
652
653 err
654 }
655
656 pub(crate) fn value_validation(
657 arg: String,
658 val: String,
659 err: Box<dyn error::Error + Send + Sync>,
660 ) -> Self {
661 let mut err = Self::new(ErrorKind::ValueValidation).set_source(err);
662
663 #[cfg(feature = "error-context")]
664 {
665 err = err.extend_context_unchecked([
666 (ContextKind::InvalidArg, ContextValue::String(arg)),
667 (ContextKind::InvalidValue, ContextValue::String(val)),
668 ]);
669 }
670
671 err
672 }
673
674 pub(crate) fn wrong_number_of_values(
675 cmd: &Command,
676 arg: String,
677 num_vals: usize,
678 curr_vals: usize,
679 usage: Option<StyledStr>,
680 ) -> Self {
681 let mut err = Self::new(ErrorKind::WrongNumberOfValues).with_cmd(cmd);
682
683 #[cfg(feature = "error-context")]
684 {
685 err = err.extend_context_unchecked([
686 (ContextKind::InvalidArg, ContextValue::String(arg)),
687 (
688 ContextKind::ExpectedNumValues,
689 ContextValue::Number(num_vals as isize),
690 ),
691 (
692 ContextKind::ActualNumValues,
693 ContextValue::Number(curr_vals as isize),
694 ),
695 ]);
696 if let Some(usage) = usage {
697 err = err
698 .insert_context_unchecked(ContextKind::Usage, ContextValue::StyledStr(usage));
699 }
700 }
701
702 err
703 }
704
705 pub(crate) fn unknown_argument(
706 cmd: &Command,
707 arg: String,
708 did_you_mean: Option<(String, Option<String>)>,
709 suggested_trailing_arg: bool,
710 usage: Option<StyledStr>,
711 ) -> Self {
712 use std::fmt::Write as _;
713 let styles = cmd.get_styles();
714 let invalid = &styles.get_invalid();
715 let valid = &styles.get_valid();
716 let mut err = Self::new(ErrorKind::UnknownArgument).with_cmd(cmd);
717
718 #[cfg(feature = "error-context")]
719 {
720 let mut suggestions = vec![];
721 if suggested_trailing_arg {
722 let mut styled_suggestion = StyledStr::new();
723 let _ = write!(
724 styled_suggestion,
725 "to pass '{invalid}{arg}{invalid:#}' as a value, use '{valid}-- {arg}{valid:#}'",
726 );
727 suggestions.push(styled_suggestion);
728 }
729
730 err = err
731 .extend_context_unchecked([(ContextKind::InvalidArg, ContextValue::String(arg))]);
732 if let Some(usage) = usage {
733 err = err
734 .insert_context_unchecked(ContextKind::Usage, ContextValue::StyledStr(usage));
735 }
736 match did_you_mean {
737 Some((flag, Some(sub))) => {
738 let mut styled_suggestion = StyledStr::new();
739 let _ = write!(styled_suggestion, "'{valid}{sub} {flag}{valid:#}' exists",);
740 suggestions.push(styled_suggestion);
741 }
742 Some((flag, None)) => {
743 err = err.insert_context_unchecked(
744 ContextKind::SuggestedArg,
745 ContextValue::String(flag),
746 );
747 }
748 None => {}
749 }
750 if !suggestions.is_empty() {
751 err = err.insert_context_unchecked(
752 ContextKind::Suggested,
753 ContextValue::StyledStrs(suggestions),
754 );
755 }
756 }
757
758 err
759 }
760
761 pub(crate) fn unnecessary_double_dash(
762 cmd: &Command,
763 arg: String,
764 usage: Option<StyledStr>,
765 ) -> Self {
766 use std::fmt::Write as _;
767 let styles = cmd.get_styles();
768 let invalid = &styles.get_invalid();
769 let valid = &styles.get_valid();
770 let mut err = Self::new(ErrorKind::UnknownArgument).with_cmd(cmd);
771
772 #[cfg(feature = "error-context")]
773 {
774 let mut styled_suggestion = StyledStr::new();
775 let _ = write!(
776 styled_suggestion,
777 "subcommand '{valid}{arg}{valid:#}' exists; to use it, remove the '{invalid}--{invalid:#}' before it",
778 );
779
780 err = err.extend_context_unchecked([
781 (ContextKind::InvalidArg, ContextValue::String(arg)),
782 (
783 ContextKind::Suggested,
784 ContextValue::StyledStrs(vec![styled_suggestion]),
785 ),
786 ]);
787 if let Some(usage) = usage {
788 err = err
789 .insert_context_unchecked(ContextKind::Usage, ContextValue::StyledStr(usage));
790 }
791 }
792
793 err
794 }
795
796 fn formatted(&self) -> Cow<'_, StyledStr> {
797 if let Some(message) = self.inner.message.as_ref() {
798 message.formatted(&self.inner.styles)
799 } else {
800 let styled = F::format_error(self);
801 Cow::Owned(styled)
802 }
803 }
804}
805
806impl<F: ErrorFormatter> From<io::Error> for Error<F> {
807 fn from(e: io::Error) -> Self {
808 Error::raw(ErrorKind::Io, e)
809 }
810}
811
812impl<F: ErrorFormatter> From<fmt::Error> for Error<F> {
813 fn from(e: fmt::Error) -> Self {
814 Error::raw(ErrorKind::Format, e)
815 }
816}
817
818impl<F: ErrorFormatter> Debug for Error<F> {
819 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
820 self.inner.fmt(f)
821 }
822}
823
824impl<F: ErrorFormatter> error::Error for Error<F> {
825 #[allow(trivial_casts)]
826 fn source(&self) -> Option<&(dyn error::Error + 'static)> {
827 self.inner.source.as_ref().map(|e| e.as_ref() as _)
828 }
829}
830
831impl<F: ErrorFormatter> Display for Error<F> {
832 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
833 ok!(write!(f, "{}", self.formatted()));
835 if let Some(backtrace) = self.inner.backtrace.as_ref() {
836 ok!(writeln!(f));
837 ok!(writeln!(f, "Backtrace:"));
838 ok!(writeln!(f, "{backtrace}"));
839 }
840 Ok(())
841 }
842}
843
844#[derive(Clone, Debug)]
845pub(crate) enum Message {
846 Raw(String),
847 Formatted(StyledStr),
848}
849
850impl Message {
851 fn format(&mut self, cmd: &Command, usage: Option<StyledStr>) {
852 match self {
853 Message::Raw(s) => {
854 let mut message = String::new();
855 std::mem::swap(s, &mut message);
856
857 let styled = format::format_error_message(
858 &message,
859 cmd.get_styles(),
860 Some(cmd),
861 usage.as_ref(),
862 );
863
864 *self = Self::Formatted(styled);
865 }
866 Message::Formatted(_) => {}
867 }
868 }
869
870 fn formatted(&self, styles: &Styles) -> Cow<'_, StyledStr> {
871 match self {
872 Message::Raw(s) => {
873 let styled = format::format_error_message(s, styles, None, None);
874
875 Cow::Owned(styled)
876 }
877 Message::Formatted(s) => Cow::Borrowed(s),
878 }
879 }
880}
881
882impl From<String> for Message {
883 fn from(inner: String) -> Self {
884 Self::Raw(inner)
885 }
886}
887
888impl From<StyledStr> for Message {
889 fn from(inner: StyledStr) -> Self {
890 Self::Formatted(inner)
891 }
892}
893
894#[cfg(feature = "debug")]
895#[derive(Debug)]
896struct Backtrace(backtrace::Backtrace);
897
898#[cfg(feature = "debug")]
899impl Backtrace {
900 fn new() -> Option<Self> {
901 Some(Self(backtrace::Backtrace::new()))
902 }
903}
904
905#[cfg(feature = "debug")]
906impl Display for Backtrace {
907 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
908 write!(f, "{:?}", self.0)
910 }
911}
912
913#[cfg(not(feature = "debug"))]
914#[derive(Debug)]
915struct Backtrace;
916
917#[cfg(not(feature = "debug"))]
918impl Backtrace {
919 fn new() -> Option<Self> {
920 None
921 }
922}
923
924#[cfg(not(feature = "debug"))]
925impl Display for Backtrace {
926 fn fmt(&self, _: &mut Formatter<'_>) -> fmt::Result {
927 Ok(())
928 }
929}
930
931#[test]
932fn check_auto_traits() {
933 static_assertions::assert_impl_all!(Error: Send, Sync, Unpin);
934}