Skip to main content

snafu/
lib.rs

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