snafu/
lib.rs

1#![deny(missing_docs)]
2#![allow(stable_features)]
3#![cfg_attr(docsrs, feature(doc_auto_cfg))]
4#![cfg_attr(not(any(feature = "std", test)), no_std)]
5#![cfg_attr(feature = "unstable-core-error", feature(error_in_core))]
6#![cfg_attr(
7    feature = "unstable-provider-api",
8    feature(error_generic_member_access)
9)]
10#![cfg_attr(feature = "unstable-try-trait", feature(try_trait_v2))]
11
12//! # SNAFU
13//!
14//! SNAFU is a library to easily generate errors and add information
15//! to underlying errors, especially when the same underlying error
16//! type can occur in different contexts.
17//!
18//! For detailed information, please see the [`Snafu`][] macro and the
19//! [user's guide](guide).
20//!
21//! ## Features
22//!
23//! - [Turnkey errors based on strings](Whatever)
24//! - [Custom error types](Snafu)
25//!   - Including a conversion path from turnkey errors
26//! - [Backtraces](Backtrace)
27//! - Extension traits for
28//!   - [`Results`](ResultExt)
29//!   - [`Options`](OptionExt)
30#![cfg_attr(feature = "futures", doc = "   - [`Futures`](futures::TryFutureExt)")]
31#![cfg_attr(feature = "futures", doc = "   - [`Streams`](futures::TryStreamExt)")]
32//! - [Error reporting](#reporting)
33//! - Suitable for libraries and applications
34//! - `no_std` compatibility
35//! - Generic types and lifetimes
36//!
37//! ## Quick start
38//!
39//! If you want to report errors without hassle, start with the
40//! [`Whatever`][] type and the [`whatever!`][] macro:
41//!
42//! ```rust
43//! use snafu::{prelude::*, Whatever};
44//!
45//! fn is_valid_id(id: u16) -> Result<(), Whatever> {
46//!     if id < 10 {
47//!         whatever!("ID may not be less than 10, but it was {id}");
48//!     }
49//!     Ok(())
50//! }
51//! ```
52//!
53//! You can also use it to wrap any other error:
54//!
55//! ```rust
56//! use snafu::{prelude::*, Whatever};
57//!
58//! fn read_config_file(path: &str) -> Result<String, Whatever> {
59//!     std::fs::read_to_string(path)
60//!         .with_whatever_context(|_| format!("Could not read file {path}"))
61//! }
62//! ```
63//!
64//! [`Whatever`][] allows for a short message and tracks a
65//! [`Backtrace`][] for every error:
66//!
67//! ```rust
68//! use snafu::{prelude::*, ErrorCompat, Whatever};
69//!
70//! # fn returns_an_error() -> Result<(), Whatever> { Ok(()) }
71//! if let Err(e) = returns_an_error() {
72//!     eprintln!("An error occurred: {e}");
73//!     if let Some(bt) = ErrorCompat::backtrace(&e) {
74//! #       #[cfg(not(feature = "backtraces-impl-backtrace-crate"))]
75//!         eprintln!("{bt}");
76//!     }
77//! }
78//! ```
79//!
80//! ## Custom error types
81//!
82//! Many projects will hit limitations of the `Whatever` type. When
83//! that occurs, it's time to create your own error type by deriving
84//! [`Snafu`][]!
85//!
86//! ### Struct style
87//!
88//! SNAFU will read your error struct definition and create a *context
89//! selector* type (called `InvalidIdSnafu` in this example). These
90//! context selectors are used with the [`ensure!`][] macro to provide
91//! ergonomic error creation:
92//!
93//! ```rust
94//! use snafu::prelude::*;
95//!
96//! #[derive(Debug, Snafu)]
97//! #[snafu(display("ID may not be less than 10, but it was {id}"))]
98//! struct InvalidIdError {
99//!     id: u16,
100//! }
101//!
102//! fn is_valid_id(id: u16) -> Result<(), InvalidIdError> {
103//!     ensure!(id >= 10, InvalidIdSnafu { id });
104//!     Ok(())
105//! }
106//! ```
107//!
108//! If you add a `source` field to your error, you can then wrap an
109//! underlying error using the [`context`](ResultExt::context)
110//! extension method:
111//!
112//! ```rust
113//! use snafu::prelude::*;
114//!
115//! #[derive(Debug, Snafu)]
116//! #[snafu(display("Could not read file {path}"))]
117//! struct ConfigFileError {
118//!     source: std::io::Error,
119//!     path: String,
120//! }
121//!
122//! fn read_config_file(path: &str) -> Result<String, ConfigFileError> {
123//!     std::fs::read_to_string(path).context(ConfigFileSnafu { path })
124//! }
125//! ```
126//!
127//! ### Enum style
128//!
129//! While error structs are good for constrained cases, they don't
130//! allow for reporting multiple possible kinds of errors at one
131//! time. Error enums solve that problem.
132//!
133//! SNAFU will read your error enum definition and create a *context
134//! selector* type for each variant (called `InvalidIdSnafu` in this
135//! example). These context selectors are used with the [`ensure!`][]
136//! macro to provide ergonomic error creation:
137//!
138//! ```rust
139//! use snafu::prelude::*;
140//!
141//! #[derive(Debug, Snafu)]
142//! enum Error {
143//!     #[snafu(display("ID may not be less than 10, but it was {id}"))]
144//!     InvalidId { id: u16 },
145//! }
146//!
147//! fn is_valid_id(id: u16) -> Result<(), Error> {
148//!     ensure!(id >= 10, InvalidIdSnafu { id });
149//!     Ok(())
150//! }
151//! ```
152//!
153//! If you add a `source` field to a variant, you can then wrap an
154//! underlying error using the [`context`](ResultExt::context)
155//! extension method:
156//!
157//! ```rust
158//! use snafu::prelude::*;
159//!
160//! #[derive(Debug, Snafu)]
161//! enum Error {
162//!     #[snafu(display("Could not read file {path}"))]
163//!     ConfigFile {
164//!         source: std::io::Error,
165//!         path: String,
166//!     },
167//! }
168//!
169//! fn read_config_file(path: &str) -> Result<String, Error> {
170//!     std::fs::read_to_string(path).context(ConfigFileSnafu { path })
171//! }
172//! ```
173//!
174//! You can combine the power of the [`whatever!`][] macro with an
175//! enum error type. This is great if you started out with
176//! [`Whatever`][] and are moving to a custom error type:
177//!
178//! ```rust
179//! use snafu::prelude::*;
180//!
181//! #[derive(Debug, Snafu)]
182//! enum Error {
183//!     #[snafu(display("ID may not be less than 10, but it was {id}"))]
184//!     InvalidId { id: u16 },
185//!
186//!     #[snafu(whatever, display("{message}"))]
187//!     Whatever {
188//!         message: String,
189//!         #[snafu(source(from(Box<dyn std::error::Error>, Some)))]
190//!         source: Option<Box<dyn std::error::Error>>,
191//!     },
192//! }
193//!
194//! fn is_valid_id(id: u16) -> Result<(), Error> {
195//!     ensure!(id >= 10, InvalidIdSnafu { id });
196//!     whatever!("Just kidding... this function always fails!");
197//!     Ok(())
198//! }
199//! ```
200//!
201//! You may wish to make the type `Send` and/or `Sync`, allowing
202//! your error type to be used in multithreaded programs, by changing
203//! `dyn std::error::Error` to `dyn std::error::Error + Send + Sync`.
204//!
205//! ## Reporting
206//!
207//! Printing an error via [`Display`][]
208//! will only show the top-level error message without the underlying sources.
209//! For an extended error report,
210//! SNAFU offers a user-friendly error output mechanism.
211//! It prints the main error and all underlying errors in the chain,
212//! from the most recent to the oldest,
213//! plus the [backtrace](Backtrace) if applicable.
214//! This is done by using the [`macro@report`] procedural macro
215//! or the [`Report`] type directly.
216//!
217//! ```no_run
218//! use snafu::prelude::*;
219//!
220//! #[derive(Debug, Snafu)]
221//! #[snafu(display("Could not load configuration file {path}"))]
222//! struct ConfigFileError {
223//!     source: std::io::Error,
224//!     path: String,
225//! }
226//!
227//! fn read_config_file(path: &str) -> Result<String, ConfigFileError> {
228//!     std::fs::read_to_string(path).context(ConfigFileSnafu { path })
229//! }
230//!
231//! #[snafu::report]
232//! fn main() -> Result<(), ConfigFileError> {
233//!     read_config_file("bad-config.ini")?;
234//!     Ok(())
235//! }
236//! ```
237//!
238//! This will print:
239//!
240//! ```none
241//! Error: Could not load configuration file bad-config.ini
242//!
243//! Caused by this error:
244//! 1: No such file or directory (os error 2)
245//! ```
246//!
247//! Which shows the underlying errors, unlike [`Display`]:
248//!
249//! ```none
250//! Error: Could not load configuration file bad-config.ini
251//! ```
252//!
253//! ... and is also more readable than the [`Debug`] output:
254//!
255//! ```none
256//! Error: ConfigFileError { source: Os { code: 2, kind: NotFound, message: "No such file or directory" }, path: "bad-config.ini" }
257//! ```
258//!
259//! [`Display`]: core::fmt::Display
260//! [`Debug`]: core::fmt::Debug
261//!
262//! ## Next steps
263//!
264//! Read the documentation for the [`Snafu`][] macro to see all of the
265//! capabilities, then read the [user's guide](guide) for deeper
266//! understanding.
267
268use core::fmt;
269
270#[cfg(feature = "alloc")]
271extern crate alloc;
272#[cfg(feature = "alloc")]
273use alloc::{boxed::Box, string::String};
274
275pub mod prelude {
276    //! Traits and macros used by most projects. Add `use
277    //! snafu::prelude::*` to your code to quickly get started with
278    //! SNAFU.
279
280    pub use crate::{ensure, OptionExt as _, ResultExt as _};
281
282    // https://github.com/rust-lang/rust/issues/89020
283    #[doc = include_str!("Snafu.md")]
284    // Links are reported as broken, but don't appear to be
285    #[allow(rustdoc::broken_intra_doc_links)]
286    pub use snafu_derive::Snafu;
287
288    #[cfg(any(feature = "alloc", test))]
289    pub use crate::{ensure_whatever, whatever};
290
291    #[cfg(feature = "futures")]
292    pub use crate::futures::{TryFutureExt as _, TryStreamExt as _};
293}
294
295#[cfg(not(any(
296    all(feature = "std", feature = "rust_1_65"),
297    feature = "backtraces-impl-backtrace-crate"
298)))]
299#[path = "backtrace_impl_inert.rs"]
300mod backtrace_impl;
301
302#[cfg(feature = "backtraces-impl-backtrace-crate")]
303#[path = "backtrace_impl_backtrace_crate.rs"]
304mod backtrace_impl;
305
306#[cfg(all(
307    feature = "std",
308    feature = "rust_1_65",
309    not(feature = "backtraces-impl-backtrace-crate")
310))]
311#[path = "backtrace_impl_std.rs"]
312mod backtrace_impl;
313
314pub use backtrace_impl::*;
315
316#[cfg(any(feature = "std", test))]
317mod once_bool;
318
319#[cfg(feature = "futures")]
320pub mod futures;
321
322mod error_chain;
323pub use crate::error_chain::*;
324
325mod report;
326#[cfg(feature = "alloc")]
327pub use report::CleanedErrorText;
328pub use report::{Report, __InternalExtractErrorType};
329
330#[doc = include_str!("Snafu.md")]
331#[doc(alias(
332    "backtrace",
333    "context",
334    "crate_root",
335    "display",
336    "implicit",
337    "module",
338    "provide",
339    "source",
340    "transparent",
341    "visibility",
342    "whatever",
343))]
344pub use snafu_derive::Snafu;
345
346#[doc = include_str!("report.md")]
347pub use snafu_derive::report;
348
349macro_rules! generate_guide {
350    (pub mod $name:ident { $($children:tt)* } $($rest:tt)*) => {
351        generate_guide!(@gen ".", pub mod $name { $($children)* } $($rest)*);
352    };
353    (@gen $prefix:expr, ) => {};
354    (@gen $prefix:expr, pub mod $name:ident; $($rest:tt)*) => {
355        generate_guide!(@gen $prefix, pub mod $name { } $($rest)*);
356    };
357    (@gen $prefix:expr, @code pub mod $name:ident; $($rest:tt)*) => {
358        #[cfg(feature = "guide")]
359        pub mod $name;
360
361        #[cfg(not(feature = "guide"))]
362        /// Not currently built; please add the `guide` feature flag.
363        pub mod $name {}
364
365        generate_guide!(@gen $prefix, $($rest)*);
366    };
367    (@gen $prefix:expr, pub mod $name:ident { $($children:tt)* } $($rest:tt)*) => {
368        #[cfg(feature = "guide")]
369        #[doc = include_str!(concat!($prefix, "/", stringify!($name), ".md"))]
370        pub mod $name {
371            use crate::*;
372            generate_guide!(@gen concat!($prefix, "/", stringify!($name)), $($children)*);
373        }
374        #[cfg(not(feature = "guide"))]
375        /// Not currently built; please add the `guide` feature flag.
376        pub mod $name {
377            generate_guide!(@gen concat!($prefix, "/", stringify!($name)), $($children)*);
378        }
379
380        generate_guide!(@gen $prefix, $($rest)*);
381    };
382}
383
384generate_guide! {
385    pub mod guide {
386        pub mod comparison {
387            pub mod failure;
388        }
389        pub mod compatibility;
390        pub mod feature_flags;
391        pub mod generics;
392        pub mod opaque;
393        pub mod philosophy;
394        pub mod structs;
395        pub mod what_code_is_generated;
396        pub mod troubleshooting {
397            pub mod missing_field_source;
398        }
399        pub mod upgrading;
400
401        @code pub mod examples;
402    }
403}
404
405#[cfg(any(feature = "rust_1_81", feature = "unstable-core-error"))]
406#[doc(hidden)]
407pub use core::error;
408
409#[cfg(any(feature = "rust_1_81", feature = "unstable-core-error"))]
410#[doc(hidden)]
411pub use core::error::Error;
412
413#[cfg(all(
414    not(any(feature = "rust_1_81", feature = "unstable-core-error")),
415    any(feature = "std", test)
416))]
417#[doc(hidden)]
418pub use std::error;
419
420#[cfg(all(
421    not(any(feature = "rust_1_81", feature = "unstable-core-error")),
422    any(feature = "std", test)
423))]
424#[doc(hidden)]
425pub use std::error::Error;
426
427#[cfg(not(any(
428    feature = "rust_1_81",
429    feature = "unstable-core-error",
430    feature = "std",
431    test
432)))]
433mod fallback_error;
434#[cfg(not(any(
435    feature = "rust_1_81",
436    feature = "unstable-core-error",
437    feature = "std",
438    test
439)))]
440#[doc(hidden)]
441pub use fallback_error::Error;
442
443/// Ensure a condition is true. If it is not, return from the function
444/// with an error.
445///
446/// ## Examples
447///
448/// ```rust
449/// use snafu::prelude::*;
450///
451/// #[derive(Debug, Snafu)]
452/// enum Error {
453///     InvalidUser { user_id: i32 },
454/// }
455///
456/// fn example(user_id: i32) -> Result<(), Error> {
457///     ensure!(user_id > 0, InvalidUserSnafu { user_id });
458///     // After this point, we know that `user_id` is positive.
459///     let user_id = user_id as u32;
460///     Ok(())
461/// }
462/// ```
463#[macro_export]
464macro_rules! ensure {
465    ($predicate:expr, $context_selector:expr $(,)?) => {
466        if !$predicate {
467            return $context_selector
468                .fail()
469                .map_err(::core::convert::Into::into);
470        }
471    };
472}
473
474#[cfg(feature = "alloc")]
475#[doc(hidden)]
476pub use alloc::format as __format;
477
478/// Instantiate and return a stringly-typed error message.
479///
480/// This can be used with the provided [`Whatever`][] type or with a
481/// custom error type that uses `snafu(whatever)`.
482///
483/// # Without an underlying error
484///
485/// Provide a format string and any optional arguments. The macro will
486/// unconditionally exit the calling function with an error.
487///
488/// ## Examples
489///
490/// ```rust
491/// use snafu::{Whatever, prelude::*};
492///
493/// type Result<T, E = Whatever> = std::result::Result<T, E>;
494///
495/// enum Status {
496///     Sleeping,
497///     Chilling,
498///     Working,
499/// }
500///
501/// # fn stand_up() {}
502/// # fn go_downstairs() {}
503/// fn do_laundry(status: Status, items: u8) -> Result<()> {
504///     match status {
505///         Status::Sleeping => whatever!("Cannot launder {items} clothes when I am asleep"),
506///         Status::Chilling => {
507///             stand_up();
508///             go_downstairs();
509///         }
510///         Status::Working => {
511///             go_downstairs();
512///         }
513///     }
514///     Ok(())
515/// }
516/// ```
517///
518/// # With an underlying error
519///
520/// Provide a `Result` as the first argument, followed by a format
521/// string and any optional arguments. If the `Result` is an error,
522/// the formatted string will be appended to the error and the macro
523/// will exit the calling function with an error. If the `Result` is
524/// not an error, the macro will evaluate to the `Ok` value of the
525/// `Result`.
526///
527/// ## Examples
528///
529/// ```rust
530/// use snafu::prelude::*;
531///
532/// #[derive(Debug, Snafu)]
533/// #[snafu(whatever, display("Error was: {message}"))]
534/// struct Error {
535///     message: String,
536///     #[snafu(source(from(Box<dyn std::error::Error>, Some)))]
537///     source: Option<Box<dyn std::error::Error>>,
538/// }
539/// type Result<T, E = Error> = std::result::Result<T, E>;
540///
541/// fn calculate_brightness_factor() -> Result<u8> {
542///     let angle = calculate_angle_of_refraction();
543///     let angle = whatever!(angle, "There was no angle");
544///     Ok(angle * 2)
545/// }
546///
547/// fn calculate_angle_of_refraction() -> Result<u8> {
548///     whatever!("The programmer forgot to implement this...");
549/// }
550/// ```
551#[macro_export]
552#[cfg(any(feature = "alloc", test))]
553macro_rules! whatever {
554    ($fmt:literal$(, $($arg:expr),* $(,)?)?) => {
555        return core::result::Result::Err({
556            $crate::FromString::without_source(
557                $crate::__format!($fmt$(, $($arg),*)*),
558            )
559        });
560    };
561    ($source:expr, $fmt:literal$(, $($arg:expr),* $(,)?)*) => {
562        match $source {
563            core::result::Result::Ok(v) => v,
564            core::result::Result::Err(e) => {
565                return core::result::Result::Err({
566                    $crate::FromString::with_source(
567                        core::convert::Into::into(e),
568                        $crate::__format!($fmt$(, $($arg),*)*),
569                    )
570                });
571            }
572        }
573    };
574}
575
576/// Ensure a condition is true. If it is not, return a stringly-typed
577/// error message.
578///
579/// This can be used with the provided [`Whatever`][] type or with a
580/// custom error type that uses `snafu(whatever)`.
581///
582/// ## Examples
583///
584/// ```rust
585/// use snafu::prelude::*;
586///
587/// #[derive(Debug, Snafu)]
588/// #[snafu(whatever, display("Error was: {message}"))]
589/// struct Error {
590///     message: String,
591/// }
592/// type Result<T, E = Error> = std::result::Result<T, E>;
593///
594/// fn get_bank_account_balance(account_id: &str) -> Result<u8> {
595/// # fn moon_is_rising() -> bool { false }
596///     ensure_whatever!(
597///         moon_is_rising(),
598///         "We are recalibrating the dynamos for account {account_id}, sorry",
599///     );
600///
601///     Ok(100)
602/// }
603/// ```
604#[macro_export]
605#[cfg(any(feature = "alloc", test))]
606macro_rules! ensure_whatever {
607    ($predicate:expr, $fmt:literal$(, $($arg:expr),* $(,)?)?) => {
608        if !$predicate {
609            $crate::whatever!($fmt$(, $($arg),*)*);
610        }
611    };
612}
613
614/// Additions to [`Result`][].
615pub trait ResultExt<T, E>: Sized {
616    /// Extend a [`Result`]'s error with additional context-sensitive information.
617    ///
618    /// [`Result`]: std::result::Result
619    ///
620    /// ```rust
621    /// use snafu::prelude::*;
622    ///
623    /// #[derive(Debug, Snafu)]
624    /// enum Error {
625    ///     Authenticating {
626    ///         user_name: String,
627    ///         user_id: i32,
628    ///         source: ApiError,
629    ///     },
630    /// }
631    ///
632    /// fn example() -> Result<(), Error> {
633    ///     another_function().context(AuthenticatingSnafu {
634    ///         user_name: "admin",
635    ///         user_id: 42,
636    ///     })?;
637    ///     Ok(())
638    /// }
639    ///
640    /// # type ApiError = Box<dyn std::error::Error>;
641    /// fn another_function() -> Result<i32, ApiError> {
642    ///     /* ... */
643    /// # Ok(42)
644    /// }
645    /// ```
646    ///
647    /// Note that the context selector will call [`Into::into`][] on each field,
648    /// so the types are not required to exactly match.
649    fn context<C, E2>(self, context: C) -> Result<T, E2>
650    where
651        C: IntoError<E2, Source = E>,
652        E2: Error + ErrorCompat;
653
654    /// Extend a [`Result`][]'s error with lazily-generated context-sensitive information.
655    ///
656    /// [`Result`]: std::result::Result
657    ///
658    /// ```rust
659    /// use snafu::prelude::*;
660    ///
661    /// #[derive(Debug, Snafu)]
662    /// enum Error {
663    ///     Authenticating {
664    ///         user_name: String,
665    ///         user_id: i32,
666    ///         source: ApiError,
667    ///     },
668    /// }
669    ///
670    /// fn example() -> Result<(), Error> {
671    ///     another_function().with_context(|_| AuthenticatingSnafu {
672    ///         user_name: "admin".to_string(),
673    ///         user_id: 42,
674    ///     })?;
675    ///     Ok(())
676    /// }
677    ///
678    /// # type ApiError = std::io::Error;
679    /// fn another_function() -> Result<i32, ApiError> {
680    ///     /* ... */
681    /// # Ok(42)
682    /// }
683    /// ```
684    ///
685    /// Note that this *may not* be needed in many cases because the context
686    /// selector will call [`Into::into`][] on each field.
687    fn with_context<F, C, E2>(self, context: F) -> Result<T, E2>
688    where
689        F: FnOnce(&mut E) -> C,
690        C: IntoError<E2, Source = E>,
691        E2: Error + ErrorCompat;
692
693    /// Extend a [`Result`]'s error with information from a string.
694    ///
695    /// The target error type must implement [`FromString`] by using
696    /// the
697    /// [`#[snafu(whatever)]`][Snafu#controlling-stringly-typed-errors]
698    /// attribute. The premade [`Whatever`] type is also available.
699    ///
700    /// In many cases, you will want to use
701    /// [`with_whatever_context`][Self::with_whatever_context] instead
702    /// as it gives you access to the error and is only called in case
703    /// of error. This method is best suited for when you have a
704    /// string literal.
705    ///
706    /// ```rust
707    /// use snafu::{prelude::*, Whatever};
708    ///
709    /// fn example() -> Result<(), Whatever> {
710    ///     std::fs::read_to_string("/this/does/not/exist")
711    ///         .whatever_context("couldn't open the file")?;
712    ///     Ok(())
713    /// }
714    ///
715    /// let err = example().unwrap_err();
716    /// assert_eq!("couldn't open the file", err.to_string());
717    /// ```
718    #[cfg(any(feature = "alloc", test))]
719    fn whatever_context<S, E2>(self, context: S) -> Result<T, E2>
720    where
721        S: Into<String>,
722        E2: FromString,
723        E: Into<E2::Source>;
724
725    /// Extend a [`Result`]'s error with information from a
726    /// lazily-generated string.
727    ///
728    /// The target error type must implement [`FromString`] by using
729    /// the
730    /// [`#[snafu(whatever)]`][Snafu#controlling-stringly-typed-errors]
731    /// attribute. The premade [`Whatever`] type is also available.
732    ///
733    /// ```rust
734    /// use snafu::{prelude::*, Whatever};
735    ///
736    /// fn example() -> Result<(), Whatever> {
737    ///     let filename = "/this/does/not/exist";
738    ///     std::fs::read_to_string(filename)
739    ///         .with_whatever_context(|_| format!("couldn't open the file {filename}"))?;
740    ///     Ok(())
741    /// }
742    ///
743    /// let err = example().unwrap_err();
744    /// assert_eq!(
745    ///     "couldn't open the file /this/does/not/exist",
746    ///     err.to_string(),
747    /// );
748    /// ```
749    ///
750    /// The closure is not called when the `Result` is `Ok`:
751    ///
752    /// ```rust
753    /// use snafu::{prelude::*, Whatever};
754    ///
755    /// let value: std::io::Result<i32> = Ok(42);
756    /// let result = value.with_whatever_context::<_, String, Whatever>(|_| {
757    ///     panic!("This block will not be evaluated");
758    /// });
759    ///
760    /// assert!(result.is_ok());
761    /// ```
762    #[cfg(any(feature = "alloc", test))]
763    fn with_whatever_context<F, S, E2>(self, context: F) -> Result<T, E2>
764    where
765        F: FnOnce(&mut E) -> S,
766        S: Into<String>,
767        E2: FromString,
768        E: Into<E2::Source>;
769
770    /// Convert a [`Result`]'s error into a boxed trait object
771    /// compatible with multiple threads.
772    ///
773    /// This is useful when you have errors of multiple types that you
774    /// wish to treat as one type. This may occur when dealing with
775    /// errors in a generic context, such as when the error is a
776    /// trait's associated type.
777    ///
778    /// In cases like this, you cannot name the original error type
779    /// without making the outer error type generic as well. Using an
780    /// error trait object offers an alternate solution.
781    ///
782    /// ```rust
783    /// # use std::convert::TryInto;
784    /// use snafu::prelude::*;
785    ///
786    /// fn convert_value_into_u8<V>(v: V) -> Result<u8, ConversionFailedError>
787    /// where
788    ///     V: TryInto<u8>,
789    ///     V::Error: snafu::Error + Send + Sync + 'static,
790    /// {
791    ///     v.try_into().boxed().context(ConversionFailedSnafu)
792    /// }
793    ///
794    /// #[derive(Debug, Snafu)]
795    /// struct ConversionFailedError {
796    ///     source: Box<dyn snafu::Error + Send + Sync + 'static>,
797    /// }
798    /// ```
799    ///
800    /// ## Avoiding misapplication
801    ///
802    /// We recommended **against** using this to create fewer error
803    /// variants which in turn would group unrelated errors. While
804    /// convenient for the programmer, doing so usually makes lower
805    /// quality error messages for the user.
806    ///
807    /// ```rust
808    /// use snafu::prelude::*;
809    /// use std::fs;
810    ///
811    /// fn do_not_do_this() -> Result<i32, UselessError> {
812    ///     let content = fs::read_to_string("/path/to/config/file")
813    ///         .boxed()
814    ///         .context(UselessSnafu)?;
815    ///     content.parse().boxed().context(UselessSnafu)
816    /// }
817    ///
818    /// #[derive(Debug, Snafu)]
819    /// struct UselessError {
820    ///     source: Box<dyn snafu::Error + Send + Sync + 'static>,
821    /// }
822    /// ```
823    #[cfg(any(feature = "alloc", test))]
824    fn boxed<'a>(self) -> Result<T, Box<dyn Error + Send + Sync + 'a>>
825    where
826        E: Error + Send + Sync + 'a;
827
828    /// Convert a [`Result`]'s error into a boxed trait object.
829    ///
830    /// This is useful when you have errors of multiple types that you
831    /// wish to treat as one type. This may occur when dealing with
832    /// errors in a generic context, such as when the error is a
833    /// trait's associated type.
834    ///
835    /// In cases like this, you cannot name the original error type
836    /// without making the outer error type generic as well. Using an
837    /// error trait object offers an alternate solution.
838    ///
839    /// ```rust
840    /// # use std::convert::TryInto;
841    /// use snafu::prelude::*;
842    ///
843    /// fn convert_value_into_u8<V>(v: V) -> Result<u8, ConversionFailedError>
844    /// where
845    ///     V: TryInto<u8>,
846    ///     V::Error: snafu::Error + 'static,
847    /// {
848    ///     v.try_into().boxed_local().context(ConversionFailedSnafu)
849    /// }
850    ///
851    /// #[derive(Debug, Snafu)]
852    /// struct ConversionFailedError {
853    ///     source: Box<dyn snafu::Error + 'static>,
854    /// }
855    /// ```
856    ///
857    /// ## Avoiding misapplication
858    ///
859    /// We recommended **against** using this to create fewer error
860    /// variants which in turn would group unrelated errors. While
861    /// convenient for the programmer, doing so usually makes lower
862    /// quality error messages for the user.
863    ///
864    /// ```rust
865    /// use snafu::prelude::*;
866    /// use std::fs;
867    ///
868    /// fn do_not_do_this() -> Result<i32, UselessError> {
869    ///     let content = fs::read_to_string("/path/to/config/file")
870    ///         .boxed_local()
871    ///         .context(UselessSnafu)?;
872    ///     content.parse().boxed_local().context(UselessSnafu)
873    /// }
874    ///
875    /// #[derive(Debug, Snafu)]
876    /// struct UselessError {
877    ///     source: Box<dyn snafu::Error + 'static>,
878    /// }
879    /// ```
880    #[cfg(any(feature = "alloc", test))]
881    fn boxed_local<'a>(self) -> Result<T, Box<dyn Error + 'a>>
882    where
883        E: Error + 'a;
884}
885
886impl<T, E> ResultExt<T, E> for Result<T, E> {
887    #[track_caller]
888    fn context<C, E2>(self, context: C) -> Result<T, E2>
889    where
890        C: IntoError<E2, Source = E>,
891        E2: Error + ErrorCompat,
892    {
893        // https://github.com/rust-lang/rust/issues/74042
894        match self {
895            Ok(v) => Ok(v),
896            Err(error) => Err(context.into_error(error)),
897        }
898    }
899
900    #[track_caller]
901    fn with_context<F, C, E2>(self, context: F) -> Result<T, E2>
902    where
903        F: FnOnce(&mut E) -> C,
904        C: IntoError<E2, Source = E>,
905        E2: Error + ErrorCompat,
906    {
907        // https://github.com/rust-lang/rust/issues/74042
908        match self {
909            Ok(v) => Ok(v),
910            Err(mut error) => {
911                let context = context(&mut error);
912                Err(context.into_error(error))
913            }
914        }
915    }
916
917    #[cfg(any(feature = "alloc", test))]
918    #[track_caller]
919    fn whatever_context<S, E2>(self, context: S) -> Result<T, E2>
920    where
921        S: Into<String>,
922        E2: FromString,
923        E: Into<E2::Source>,
924    {
925        // https://github.com/rust-lang/rust/issues/74042
926        match self {
927            Ok(v) => Ok(v),
928            Err(error) => Err(FromString::with_source(error.into(), context.into())),
929        }
930    }
931
932    #[cfg(any(feature = "alloc", test))]
933    #[track_caller]
934    fn with_whatever_context<F, S, E2>(self, context: F) -> Result<T, E2>
935    where
936        F: FnOnce(&mut E) -> S,
937        S: Into<String>,
938        E2: FromString,
939        E: Into<E2::Source>,
940    {
941        // https://github.com/rust-lang/rust/issues/74042
942        match self {
943            Ok(t) => Ok(t),
944            Err(mut e) => {
945                let context = context(&mut e);
946                Err(FromString::with_source(e.into(), context.into()))
947            }
948        }
949    }
950
951    #[cfg(any(feature = "alloc", test))]
952    fn boxed<'a>(self) -> Result<T, Box<dyn Error + Send + Sync + 'a>>
953    where
954        E: Error + Send + Sync + 'a,
955    {
956        self.map_err(|e| Box::new(e) as _)
957    }
958
959    #[cfg(any(feature = "alloc", test))]
960    fn boxed_local<'a>(self) -> Result<T, Box<dyn Error + 'a>>
961    where
962        E: Error + 'a,
963    {
964        self.map_err(|e| Box::new(e) as _)
965    }
966}
967
968/// A temporary error type used when converting an [`Option`][] into a
969/// [`Result`][]
970///
971/// [`Option`]: std::option::Option
972/// [`Result`]: std::result::Result
973pub struct NoneError;
974
975/// Additions to [`Option`][].
976pub trait OptionExt<T>: Sized {
977    /// Convert an [`Option`][] into a [`Result`][] with additional
978    /// context-sensitive information.
979    ///
980    /// [Option]: std::option::Option
981    /// [Result]: std::result::Result
982    ///
983    /// ```rust
984    /// use snafu::prelude::*;
985    ///
986    /// #[derive(Debug, Snafu)]
987    /// enum Error {
988    ///     UserLookup { user_id: i32 },
989    /// }
990    ///
991    /// fn example(user_id: i32) -> Result<(), Error> {
992    ///     let name = username(user_id).context(UserLookupSnafu { user_id })?;
993    ///     println!("Username was {name}");
994    ///     Ok(())
995    /// }
996    ///
997    /// fn username(user_id: i32) -> Option<String> {
998    ///     /* ... */
999    /// # None
1000    /// }
1001    /// ```
1002    ///
1003    /// Note that the context selector will call [`Into::into`][] on each field,
1004    /// so the types are not required to exactly match.
1005    fn context<C, E>(self, context: C) -> Result<T, E>
1006    where
1007        C: IntoError<E, Source = NoneError>,
1008        E: Error + ErrorCompat;
1009
1010    /// Convert an [`Option`][] into a [`Result`][] with
1011    /// lazily-generated context-sensitive information.
1012    ///
1013    /// [`Option`]: std::option::Option
1014    /// [`Result`]: std::result::Result
1015    ///
1016    /// ```
1017    /// use snafu::prelude::*;
1018    ///
1019    /// #[derive(Debug, Snafu)]
1020    /// enum Error {
1021    ///     UserLookup {
1022    ///         user_id: i32,
1023    ///         previous_ids: Vec<i32>,
1024    ///     },
1025    /// }
1026    ///
1027    /// fn example(user_id: i32) -> Result<(), Error> {
1028    ///     let name = username(user_id).with_context(|| UserLookupSnafu {
1029    ///         user_id,
1030    ///         previous_ids: Vec::new(),
1031    ///     })?;
1032    ///     println!("Username was {name}");
1033    ///     Ok(())
1034    /// }
1035    ///
1036    /// fn username(user_id: i32) -> Option<String> {
1037    ///     /* ... */
1038    /// # None
1039    /// }
1040    /// ```
1041    ///
1042    /// Note that this *may not* be needed in many cases because the context
1043    /// selector will call [`Into::into`][] on each field.
1044    fn with_context<F, C, E>(self, context: F) -> Result<T, E>
1045    where
1046        F: FnOnce() -> C,
1047        C: IntoError<E, Source = NoneError>,
1048        E: Error + ErrorCompat;
1049
1050    /// Convert an [`Option`] into a [`Result`] with information
1051    /// from a string.
1052    ///
1053    /// The target error type must implement [`FromString`] by using
1054    /// the
1055    /// [`#[snafu(whatever)]`][Snafu#controlling-stringly-typed-errors]
1056    /// attribute. The premade [`Whatever`] type is also available.
1057    ///
1058    /// In many cases, you will want to use
1059    /// [`with_whatever_context`][Self::with_whatever_context] instead
1060    /// as it is only called in case of error. This method is best
1061    /// suited for when you have a string literal.
1062    ///
1063    /// ```rust
1064    /// use snafu::{prelude::*, Whatever};
1065    ///
1066    /// fn example(env_var_name: &str) -> Result<(), Whatever> {
1067    ///     std::env::var_os(env_var_name).whatever_context("couldn't get the environment variable")?;
1068    ///     Ok(())
1069    /// }
1070    ///
1071    /// let err = example("UNDEFINED_ENVIRONMENT_VARIABLE").unwrap_err();
1072    /// assert_eq!("couldn't get the environment variable", err.to_string());
1073    /// ```
1074    #[cfg(any(feature = "alloc", test))]
1075    fn whatever_context<S, E>(self, context: S) -> Result<T, E>
1076    where
1077        S: Into<String>,
1078        E: FromString;
1079
1080    /// Convert an [`Option`] into a [`Result`][] with information from a
1081    /// lazily-generated string.
1082    ///
1083    /// The target error type must implement [`FromString`][] by using
1084    /// the
1085    /// [`#[snafu(whatever)]`][Snafu#controlling-stringly-typed-errors]
1086    /// attribute. The premade [`Whatever`][] type is also available.
1087    ///
1088    /// ```rust
1089    /// use snafu::{prelude::*, Whatever};
1090    ///
1091    /// fn example(env_var_name: &str) -> Result<(), Whatever> {
1092    ///     std::env::var_os(env_var_name).with_whatever_context(|| {
1093    ///         format!("couldn't get the environment variable {env_var_name}")
1094    ///     })?;
1095    ///     Ok(())
1096    /// }
1097    ///
1098    /// let err = example("UNDEFINED_ENVIRONMENT_VARIABLE").unwrap_err();
1099    /// assert_eq!(
1100    ///     "couldn't get the environment variable UNDEFINED_ENVIRONMENT_VARIABLE",
1101    ///     err.to_string()
1102    /// );
1103    /// ```
1104    ///
1105    /// The closure is not called when the `Option` is `Some`:
1106    ///
1107    /// ```rust
1108    /// use snafu::{prelude::*, Whatever};
1109    ///
1110    /// let value = Some(42);
1111    /// let result = value.with_whatever_context::<_, String, Whatever>(|| {
1112    ///     panic!("This block will not be evaluated");
1113    /// });
1114    ///
1115    /// assert!(result.is_ok());
1116    /// ```
1117    #[cfg(any(feature = "alloc", test))]
1118    fn with_whatever_context<F, S, E>(self, context: F) -> Result<T, E>
1119    where
1120        F: FnOnce() -> S,
1121        S: Into<String>,
1122        E: FromString;
1123}
1124
1125impl<T> OptionExt<T> for Option<T> {
1126    #[track_caller]
1127    fn context<C, E>(self, context: C) -> Result<T, E>
1128    where
1129        C: IntoError<E, Source = NoneError>,
1130        E: Error + ErrorCompat,
1131    {
1132        // https://github.com/rust-lang/rust/issues/74042
1133        match self {
1134            Some(v) => Ok(v),
1135            None => Err(context.into_error(NoneError)),
1136        }
1137    }
1138
1139    #[track_caller]
1140    fn with_context<F, C, E>(self, context: F) -> Result<T, E>
1141    where
1142        F: FnOnce() -> C,
1143        C: IntoError<E, Source = NoneError>,
1144        E: Error + ErrorCompat,
1145    {
1146        // https://github.com/rust-lang/rust/issues/74042
1147        match self {
1148            Some(v) => Ok(v),
1149            None => Err(context().into_error(NoneError)),
1150        }
1151    }
1152
1153    #[cfg(any(feature = "alloc", test))]
1154    #[track_caller]
1155    fn whatever_context<S, E>(self, context: S) -> Result<T, E>
1156    where
1157        S: Into<String>,
1158        E: FromString,
1159    {
1160        match self {
1161            Some(v) => Ok(v),
1162            None => Err(FromString::without_source(context.into())),
1163        }
1164    }
1165
1166    #[cfg(any(feature = "alloc", test))]
1167    #[track_caller]
1168    fn with_whatever_context<F, S, E>(self, context: F) -> Result<T, E>
1169    where
1170        F: FnOnce() -> S,
1171        S: Into<String>,
1172        E: FromString,
1173    {
1174        match self {
1175            Some(v) => Ok(v),
1176            None => {
1177                let context = context();
1178                Err(FromString::without_source(context.into()))
1179            }
1180        }
1181    }
1182}
1183
1184/// Backports changes to the [`Error`][] trait to versions of Rust
1185/// lacking them.
1186///
1187/// It is recommended to always call these methods explicitly so that
1188/// it is easy to replace usages of this trait when you start
1189/// supporting a newer version of Rust.
1190///
1191/// ```
1192/// # use snafu::{prelude::*, ErrorCompat};
1193/// # #[derive(Debug, Snafu)] enum Example {};
1194/// # fn example(error: Example) {
1195/// ErrorCompat::backtrace(&error); // Recommended
1196/// error.backtrace();              // Discouraged
1197/// # }
1198/// ```
1199pub trait ErrorCompat {
1200    /// Returns a [`Backtrace`][] that may be printed.
1201    fn backtrace(&self) -> Option<&Backtrace> {
1202        None
1203    }
1204
1205    /// Returns an iterator for traversing the chain of errors,
1206    /// starting with the current error
1207    /// and continuing with recursive calls to `Error::source`.
1208    ///
1209    /// To omit the current error and only traverse its sources,
1210    /// use `skip(1)`.
1211    fn iter_chain(&self) -> ChainCompat
1212    where
1213        Self: AsErrorSource,
1214    {
1215        ChainCompat::new(self.as_error_source())
1216    }
1217}
1218
1219impl<'a, E> ErrorCompat for &'a E
1220where
1221    E: ErrorCompat,
1222{
1223    fn backtrace(&self) -> Option<&Backtrace> {
1224        (**self).backtrace()
1225    }
1226}
1227
1228#[cfg(any(feature = "alloc", test))]
1229impl<E> ErrorCompat for Box<E>
1230where
1231    E: ErrorCompat,
1232{
1233    fn backtrace(&self) -> Option<&Backtrace> {
1234        (**self).backtrace()
1235    }
1236}
1237
1238/// Converts the receiver into an [`Error`][] trait object, suitable
1239/// for use in [`Error::source`][].
1240///
1241/// It is expected that most users of SNAFU will not directly interact
1242/// with this trait.
1243///
1244/// [`Error`]: std::error::Error
1245/// [`Error::source`]: std::error::Error::source
1246//
1247// Given an error enum with multiple types of underlying causes:
1248//
1249// ```rust
1250// enum Error {
1251//     BoxTraitObjectSendSync(Box<dyn error::Error + Send + Sync + 'static>),
1252//     BoxTraitObject(Box<dyn error::Error + 'static>),
1253//     Boxed(Box<io::Error>),
1254//     Unboxed(io::Error),
1255// }
1256// ```
1257//
1258// This trait provides the answer to what consistent expression can go
1259// in each match arm:
1260//
1261// ```rust
1262// impl error::Error for Error {
1263//     fn source(&self) -> Option<&(dyn error::Error + 'static)> {
1264//         use Error::*;
1265//
1266//         let v = match *self {
1267//             BoxTraitObjectSendSync(ref e) => ...,
1268//             BoxTraitObject(ref e) => ...,
1269//             Boxed(ref e) => ...,
1270//             Unboxed(ref e) => ...,
1271//         };
1272//
1273//         Some(v)
1274//     }
1275// }
1276//
1277// Existing methods like returning `e`, `&**e`, `Borrow::borrow(e)`,
1278// `Deref::deref(e)`, and `AsRef::as_ref(e)` do not work for various
1279// reasons.
1280pub trait AsErrorSource {
1281    /// For maximum effectiveness, this needs to be called as a method
1282    /// to benefit from Rust's automatic dereferencing of method
1283    /// receivers.
1284    fn as_error_source(&self) -> &(dyn Error + 'static);
1285}
1286
1287impl AsErrorSource for dyn Error + 'static {
1288    fn as_error_source(&self) -> &(dyn Error + 'static) {
1289        self
1290    }
1291}
1292
1293impl AsErrorSource for dyn Error + Send + 'static {
1294    fn as_error_source(&self) -> &(dyn Error + 'static) {
1295        self
1296    }
1297}
1298
1299impl AsErrorSource for dyn Error + Sync + 'static {
1300    fn as_error_source(&self) -> &(dyn Error + 'static) {
1301        self
1302    }
1303}
1304
1305impl AsErrorSource for dyn Error + Send + Sync + 'static {
1306    fn as_error_source(&self) -> &(dyn Error + 'static) {
1307        self
1308    }
1309}
1310
1311impl<T> AsErrorSource for T
1312where
1313    T: Error + 'static,
1314{
1315    fn as_error_source(&self) -> &(dyn Error + 'static) {
1316        self
1317    }
1318}
1319
1320/// Combines an underlying error with additional information
1321/// about the error.
1322///
1323/// It is expected that most users of SNAFU will not directly interact
1324/// with this trait.
1325pub trait IntoError<E>
1326where
1327    E: Error + ErrorCompat,
1328{
1329    /// The underlying error
1330    type Source;
1331
1332    /// Combine the information to produce the error
1333    fn into_error(self, source: Self::Source) -> E;
1334}
1335
1336/// Takes a string message and builds the corresponding error.
1337///
1338/// It is expected that most users of SNAFU will not directly interact
1339/// with this trait.
1340#[cfg(any(feature = "alloc", test))]
1341pub trait FromString {
1342    /// The underlying error
1343    type Source;
1344
1345    /// Create a brand new error from the given string
1346    fn without_source(message: String) -> Self;
1347
1348    /// Wrap an existing error with the given string
1349    fn with_source(source: Self::Source, message: String) -> Self;
1350}
1351
1352/// Construct data to be included as part of an error. The data must
1353/// require no arguments to be created.
1354pub trait GenerateImplicitData {
1355    /// Build the data.
1356    fn generate() -> Self;
1357
1358    /// Build the data using the given source
1359    #[track_caller]
1360    fn generate_with_source(source: &dyn crate::Error) -> Self
1361    where
1362        Self: Sized,
1363    {
1364        let _source = source;
1365        Self::generate()
1366    }
1367}
1368
1369/// View a backtrace-like value as an optional backtrace.
1370pub trait AsBacktrace {
1371    /// Retrieve the optional backtrace
1372    fn as_backtrace(&self) -> Option<&Backtrace>;
1373}
1374
1375/// Only create a backtrace when an environment variable is set.
1376///
1377/// This looks first for the value of `RUST_LIB_BACKTRACE` then
1378/// `RUST_BACKTRACE`. If the value is set to `1`, backtraces will be
1379/// enabled.
1380///
1381/// This value will be tested only once per program execution;
1382/// changing the environment variable after it has been checked will
1383/// have no effect.
1384///
1385/// ## Interaction with the Provider API
1386///
1387/// If you enable the [`unstable-provider-api` feature
1388/// flag][provider-ff], a backtrace will not be captured if the
1389/// original error is able to provide a `Backtrace`, even if the
1390/// appropriate environment variables are set. This prevents capturing
1391/// a redundant backtrace.
1392///
1393/// [provider-ff]: crate::guide::feature_flags#unstable-provider-api
1394#[cfg(any(feature = "std", test))]
1395impl GenerateImplicitData for Option<Backtrace> {
1396    fn generate() -> Self {
1397        if backtrace_collection_enabled() {
1398            Some(Backtrace::generate())
1399        } else {
1400            None
1401        }
1402    }
1403
1404    fn generate_with_source(source: &dyn crate::Error) -> Self {
1405        #[cfg(feature = "unstable-provider-api")]
1406        {
1407            if !backtrace_collection_enabled() {
1408                None
1409            } else if error::request_ref::<Backtrace>(source).is_some() {
1410                None
1411            } else {
1412                Some(Backtrace::generate_with_source(source))
1413            }
1414        }
1415
1416        #[cfg(not(feature = "unstable-provider-api"))]
1417        {
1418            let _source = source;
1419            Self::generate()
1420        }
1421    }
1422}
1423
1424#[cfg(any(feature = "std", test))]
1425impl AsBacktrace for Option<Backtrace> {
1426    fn as_backtrace(&self) -> Option<&Backtrace> {
1427        self.as_ref()
1428    }
1429}
1430
1431#[cfg(any(feature = "std", test))]
1432fn backtrace_collection_enabled() -> bool {
1433    use crate::once_bool::OnceBool;
1434    use std::env;
1435
1436    static ENABLED: OnceBool = OnceBool::new();
1437
1438    ENABLED.get(|| {
1439        // TODO: What values count as "true"?
1440        env::var_os("RUST_LIB_BACKTRACE")
1441            .or_else(|| env::var_os("RUST_BACKTRACE"))
1442            .map_or(false, |v| v == "1")
1443    })
1444}
1445
1446/// The source code location where the error was reported.
1447///
1448/// To use it, add a field of type `Location` to your error and
1449/// register it as [implicitly generated data][implicit]. When
1450/// constructing the error, you do not need to provide the location:
1451///
1452/// ```rust
1453/// # use snafu::prelude::*;
1454/// #[derive(Debug, Snafu)]
1455/// struct NeighborhoodError {
1456///     #[snafu(implicit)]
1457///     loc: snafu::Location,
1458/// }
1459///
1460/// fn check_next_door() -> Result<(), NeighborhoodError> {
1461///     ensure!(everything_quiet(), NeighborhoodSnafu);
1462///     Ok(())
1463/// }
1464/// # fn everything_quiet() -> bool { false }
1465/// ```
1466///
1467/// [implicit]: Snafu#controlling-implicitly-generated-data
1468///
1469/// ## Limitations
1470///
1471/// ### Disabled context selectors
1472///
1473/// If you have [disabled the context selector][disabled], SNAFU will
1474/// not be able to capture an accurate location.
1475///
1476/// As a workaround, re-enable the context selector.
1477///
1478/// [disabled]: Snafu#disabling-the-context-selector
1479///
1480/// ### Asynchronous code
1481///
1482/// When using SNAFU's
1483#[cfg_attr(feature = "futures", doc = " [`TryFutureExt`][futures::TryFutureExt]")]
1484#[cfg_attr(not(feature = "futures"), doc = " `TryFutureExt`")]
1485/// or
1486#[cfg_attr(feature = "futures", doc = " [`TryStreamExt`][futures::TryStreamExt]")]
1487#[cfg_attr(not(feature = "futures"), doc = " `TryStreamExt`")]
1488/// extension traits, the automatically captured location will
1489/// correspond to where the future or stream was **polled**, not where
1490/// it was created. Additionally, many `Future` or `Stream`
1491/// combinators do not forward the caller's location to their
1492/// closures, causing the recorded location to be inside of the future
1493/// combinator's library.
1494///
1495/// There are two workarounds:
1496/// 1. Use the [`location!`] macro
1497/// 1. Use [`ResultExt`] instead
1498///
1499/// ```rust
1500/// # #[cfg(feature = "futures")] {
1501/// # use snafu::{prelude::*, Location, location};
1502/// // Non-ideal: will report where `wrapped_error_future` is `.await`ed.
1503/// # let error_future = async { AnotherSnafu.fail::<()>() };
1504/// let wrapped_error_future = error_future.context(ImplicitLocationSnafu);
1505///
1506/// // Better: will report the location of `.context`.
1507/// # let error_future = async { AnotherSnafu.fail::<()>() };
1508/// let wrapped_error_future = async { error_future.await.context(ImplicitLocationSnafu) };
1509///
1510/// // Better: Will report the location of `location!`
1511/// # let error_future = async { AnotherSnafu.fail::<()>() };
1512/// let wrapped_error_future = error_future.with_context(|_| ExplicitLocationSnafu {
1513///     location: location!(),
1514/// });
1515///
1516/// # #[derive(Debug, Snafu)] struct AnotherError;
1517/// #[derive(Debug, Snafu)]
1518/// struct ImplicitLocationError {
1519///     source: AnotherError,
1520///     #[snafu(implicit)]
1521///     location: Location,
1522/// }
1523///
1524/// #[derive(Debug, Snafu)]
1525/// struct ExplicitLocationError {
1526///     source: AnotherError,
1527///     location: Location,
1528/// }
1529/// # }
1530/// ```
1531#[derive(Copy, Clone)]
1532#[non_exhaustive]
1533pub struct Location {
1534    /// The file where the error was reported
1535    pub file: &'static str,
1536    /// The line where the error was reported
1537    pub line: u32,
1538    /// The column where the error was reported
1539    pub column: u32,
1540}
1541
1542impl Location {
1543    /// Constructs a `Location` using the given information
1544    pub fn new(file: &'static str, line: u32, column: u32) -> Self {
1545        Self { file, line, column }
1546    }
1547}
1548
1549impl Default for Location {
1550    #[track_caller]
1551    fn default() -> Self {
1552        let loc = core::panic::Location::caller();
1553        Self {
1554            file: loc.file(),
1555            line: loc.line(),
1556            column: loc.column(),
1557        }
1558    }
1559}
1560
1561impl GenerateImplicitData for Location {
1562    #[inline]
1563    #[track_caller]
1564    fn generate() -> Self {
1565        Self::default()
1566    }
1567}
1568
1569impl fmt::Debug for Location {
1570    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1571        f.debug_struct("Location")
1572            .field("file", &self.file)
1573            .field("line", &self.line)
1574            .field("column", &self.column)
1575            .finish()
1576    }
1577}
1578
1579impl fmt::Display for Location {
1580    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1581        write!(
1582            f,
1583            "{file}:{line}:{column}",
1584            file = self.file,
1585            line = self.line,
1586            column = self.column,
1587        )
1588    }
1589}
1590
1591/// Constructs a [`Location`] using the current file, line, and column.
1592#[macro_export]
1593macro_rules! location {
1594    () => {
1595        $crate::Location::new(file!(), line!(), column!())
1596    };
1597}
1598
1599/// A basic error type that you can use as a first step to better
1600/// error handling.
1601///
1602/// You can use this type in your own application as a quick way to
1603/// create errors or add basic context to another error. This can also
1604/// be used in a library, but consider wrapping it in an
1605/// [opaque](guide::opaque) error to avoid putting the SNAFU crate in
1606/// your public API.
1607///
1608/// ## Examples
1609///
1610/// ```rust
1611/// use snafu::prelude::*;
1612///
1613/// type Result<T, E = snafu::Whatever> = std::result::Result<T, E>;
1614///
1615/// fn subtract_numbers(a: u32, b: u32) -> Result<u32> {
1616///     if a > b {
1617///         Ok(a - b)
1618///     } else {
1619///         whatever!("Can't subtract {a} - {b}")
1620///     }
1621/// }
1622///
1623/// fn complicated_math(a: u32, b: u32) -> Result<u32> {
1624///     let val = subtract_numbers(a, b).whatever_context("Can't do the math")?;
1625///     Ok(val * 2)
1626/// }
1627/// ```
1628///
1629/// See [`whatever!`][] for detailed usage instructions.
1630///
1631/// ## Limitations
1632///
1633/// When wrapping errors, only the backtrace from the shallowest
1634/// function is guaranteed to be available. If you need the deepest
1635/// possible trace, consider creating a custom error type and [using
1636/// `#[snafu(backtrace)]` on the `source`
1637/// field](Snafu#controlling-backtraces). If a best-effort attempt is
1638/// sufficient, see the [`backtrace`][Self::backtrace] method.
1639///
1640/// When the standard library stabilizes backtrace support, this
1641/// behavior may change.
1642#[derive(Debug, Snafu)]
1643#[snafu(crate_root(crate))]
1644#[snafu(whatever)]
1645#[snafu(display("{message}"))]
1646#[snafu(provide(opt, ref, chain, dyn std::error::Error => source.as_deref()))]
1647#[cfg(any(feature = "alloc", test))]
1648pub struct Whatever {
1649    #[snafu(source(from(Box<dyn crate::Error>, Some)))]
1650    #[snafu(provide(false))]
1651    source: Option<Box<dyn crate::Error>>,
1652    message: String,
1653    backtrace: Backtrace,
1654}
1655
1656#[cfg(any(feature = "alloc", test))]
1657impl Whatever {
1658    /// Gets the backtrace from the deepest `Whatever` error. If none
1659    /// of the underlying errors are `Whatever`, returns the backtrace
1660    /// from when this instance was created.
1661    pub fn backtrace(&self) -> Option<&Backtrace> {
1662        let mut best_backtrace = &self.backtrace;
1663
1664        let mut source = self.source();
1665        while let Some(s) = source {
1666            if let Some(this) = s.downcast_ref::<Self>() {
1667                best_backtrace = &this.backtrace;
1668            }
1669            source = s.source();
1670        }
1671
1672        Some(best_backtrace)
1673    }
1674}
1675
1676mod tests {
1677    #[cfg(doc)]
1678    #[doc = include_str!("../README.md")]
1679    fn readme_tests() {}
1680}