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
638    /// Extend a [`Result`][]'s error with lazily-generated context-sensitive information.
639    ///
640    /// [`Result`]: std::result::Result
641    ///
642    /// ```rust
643    /// use snafu::prelude::*;
644    ///
645    /// #[derive(Debug, Snafu)]
646    /// enum Error {
647    ///     Authenticating {
648    ///         user_name: String,
649    ///         user_id: i32,
650    ///         source: ApiError,
651    ///     },
652    /// }
653    ///
654    /// fn example() -> Result<(), Error> {
655    ///     another_function().with_context(|_| AuthenticatingSnafu {
656    ///         user_name: "admin".to_string(),
657    ///         user_id: 42,
658    ///     })?;
659    ///     Ok(())
660    /// }
661    ///
662    /// # type ApiError = std::io::Error;
663    /// fn another_function() -> Result<i32, ApiError> {
664    ///     /* ... */
665    /// # Ok(42)
666    /// }
667    /// ```
668    ///
669    /// Note that this *may not* be needed in many cases because the context
670    /// selector will call [`Into::into`][] on each field.
671    fn with_context<F, C, E2>(self, context: F) -> Result<T, E2>
672    where
673        F: FnOnce(&mut E) -> C,
674        C: IntoError<E2, Source = E>;
675
676    /// Extend a [`Result`]'s error with information from a string.
677    ///
678    /// The target error type must implement [`FromString`] by using
679    /// the
680    /// [`#[snafu(whatever)]`][Snafu#controlling-stringly-typed-errors]
681    /// attribute. The premade [`Whatever`] type is also available.
682    ///
683    /// In many cases, you will want to use
684    /// [`with_whatever_context`][Self::with_whatever_context] instead
685    /// as it gives you access to the error and is only called in case
686    /// of error. This method is best suited for when you have a
687    /// string literal.
688    ///
689    /// ```rust
690    /// use snafu::{prelude::*, Whatever};
691    ///
692    /// fn example() -> Result<(), Whatever> {
693    ///     std::fs::read_to_string("/this/does/not/exist")
694    ///         .whatever_context("couldn't open the file")?;
695    ///     Ok(())
696    /// }
697    ///
698    /// let err = example().unwrap_err();
699    /// assert_eq!("couldn't open the file", err.to_string());
700    /// ```
701    #[cfg(any(feature = "alloc", test))]
702    fn whatever_context<S, E2>(self, context: S) -> Result<T, E2>
703    where
704        S: Into<String>,
705        E2: FromString,
706        E: Into<E2::Source>;
707
708    /// Extend a [`Result`]'s error with information from a
709    /// lazily-generated string.
710    ///
711    /// The target error type must implement [`FromString`] by using
712    /// the
713    /// [`#[snafu(whatever)]`][Snafu#controlling-stringly-typed-errors]
714    /// attribute. The premade [`Whatever`] type is also available.
715    ///
716    /// ```rust
717    /// use snafu::{prelude::*, Whatever};
718    ///
719    /// fn example() -> Result<(), Whatever> {
720    ///     let filename = "/this/does/not/exist";
721    ///     std::fs::read_to_string(filename)
722    ///         .with_whatever_context(|_| format!("couldn't open the file {filename}"))?;
723    ///     Ok(())
724    /// }
725    ///
726    /// let err = example().unwrap_err();
727    /// assert_eq!(
728    ///     "couldn't open the file /this/does/not/exist",
729    ///     err.to_string(),
730    /// );
731    /// ```
732    ///
733    /// The closure is not called when the `Result` is `Ok`:
734    ///
735    /// ```rust
736    /// use snafu::{prelude::*, Whatever};
737    ///
738    /// let value: std::io::Result<i32> = Ok(42);
739    /// let result = value.with_whatever_context::<_, String, Whatever>(|_| {
740    ///     panic!("This block will not be evaluated");
741    /// });
742    ///
743    /// assert!(result.is_ok());
744    /// ```
745    #[cfg(any(feature = "alloc", test))]
746    fn with_whatever_context<F, S, E2>(self, context: F) -> Result<T, E2>
747    where
748        F: FnOnce(&mut E) -> S,
749        S: Into<String>,
750        E2: FromString,
751        E: Into<E2::Source>;
752
753    /// Convert a [`Result`]'s error into a boxed trait object
754    /// compatible with multiple threads.
755    ///
756    /// This is useful when you have errors of multiple types that you
757    /// wish to treat as one type. This may occur when dealing with
758    /// errors in a generic context, such as when the error is a
759    /// trait's associated type.
760    ///
761    /// In cases like this, you cannot name the original error type
762    /// without making the outer error type generic as well. Using an
763    /// error trait object offers an alternate solution.
764    ///
765    /// ```rust
766    /// # use std::convert::TryInto;
767    /// use snafu::prelude::*;
768    ///
769    /// fn convert_value_into_u8<V>(v: V) -> Result<u8, ConversionFailedError>
770    /// where
771    ///     V: TryInto<u8>,
772    ///     V::Error: snafu::Error + Send + Sync + 'static,
773    /// {
774    ///     v.try_into().boxed().context(ConversionFailedSnafu)
775    /// }
776    ///
777    /// #[derive(Debug, Snafu)]
778    /// struct ConversionFailedError {
779    ///     source: Box<dyn snafu::Error + Send + Sync + 'static>,
780    /// }
781    /// ```
782    ///
783    /// ## Avoiding misapplication
784    ///
785    /// We recommended **against** using this to create fewer error
786    /// variants which in turn would group unrelated errors. While
787    /// convenient for the programmer, doing so usually makes lower
788    /// quality error messages for the user.
789    ///
790    /// ```rust
791    /// use snafu::prelude::*;
792    /// use std::fs;
793    ///
794    /// fn do_not_do_this() -> Result<i32, UselessError> {
795    ///     let content = fs::read_to_string("/path/to/config/file")
796    ///         .boxed()
797    ///         .context(UselessSnafu)?;
798    ///     content.parse().boxed().context(UselessSnafu)
799    /// }
800    ///
801    /// #[derive(Debug, Snafu)]
802    /// struct UselessError {
803    ///     source: Box<dyn snafu::Error + Send + Sync + 'static>,
804    /// }
805    /// ```
806    #[cfg(any(feature = "alloc", test))]
807    fn boxed<'a>(self) -> Result<T, Box<dyn Error + Send + Sync + 'a>>
808    where
809        E: Error + Send + Sync + 'a;
810
811    /// Convert a [`Result`]'s error into a boxed trait object.
812    ///
813    /// This is useful when you have errors of multiple types that you
814    /// wish to treat as one type. This may occur when dealing with
815    /// errors in a generic context, such as when the error is a
816    /// trait's associated type.
817    ///
818    /// In cases like this, you cannot name the original error type
819    /// without making the outer error type generic as well. Using an
820    /// error trait object offers an alternate solution.
821    ///
822    /// ```rust
823    /// # use std::convert::TryInto;
824    /// use snafu::prelude::*;
825    ///
826    /// fn convert_value_into_u8<V>(v: V) -> Result<u8, ConversionFailedError>
827    /// where
828    ///     V: TryInto<u8>,
829    ///     V::Error: snafu::Error + 'static,
830    /// {
831    ///     v.try_into().boxed_local().context(ConversionFailedSnafu)
832    /// }
833    ///
834    /// #[derive(Debug, Snafu)]
835    /// struct ConversionFailedError {
836    ///     source: Box<dyn snafu::Error + 'static>,
837    /// }
838    /// ```
839    ///
840    /// ## Avoiding misapplication
841    ///
842    /// We recommended **against** using this to create fewer error
843    /// variants which in turn would group unrelated errors. While
844    /// convenient for the programmer, doing so usually makes lower
845    /// quality error messages for the user.
846    ///
847    /// ```rust
848    /// use snafu::prelude::*;
849    /// use std::fs;
850    ///
851    /// fn do_not_do_this() -> Result<i32, UselessError> {
852    ///     let content = fs::read_to_string("/path/to/config/file")
853    ///         .boxed_local()
854    ///         .context(UselessSnafu)?;
855    ///     content.parse().boxed_local().context(UselessSnafu)
856    /// }
857    ///
858    /// #[derive(Debug, Snafu)]
859    /// struct UselessError {
860    ///     source: Box<dyn snafu::Error + 'static>,
861    /// }
862    /// ```
863    #[cfg(any(feature = "alloc", test))]
864    fn boxed_local<'a>(self) -> Result<T, Box<dyn Error + 'a>>
865    where
866        E: Error + 'a;
867}
868
869impl<T, E> ResultExt<T, E> for Result<T, E> {
870    #[track_caller]
871    fn context<C, E2>(self, context: C) -> Result<T, E2>
872    where
873        C: IntoError<E2, Source = E>,
874    {
875        // https://github.com/rust-lang/rust/issues/74042
876        match self {
877            Ok(v) => Ok(v),
878            Err(error) => Err(context.into_error(error)),
879        }
880    }
881
882    #[track_caller]
883    fn with_context<F, C, E2>(self, context: F) -> Result<T, E2>
884    where
885        F: FnOnce(&mut E) -> C,
886        C: IntoError<E2, Source = E>,
887    {
888        // https://github.com/rust-lang/rust/issues/74042
889        match self {
890            Ok(v) => Ok(v),
891            Err(mut error) => {
892                let context = context(&mut error);
893                Err(context.into_error(error))
894            }
895        }
896    }
897
898    #[cfg(any(feature = "alloc", test))]
899    #[track_caller]
900    fn whatever_context<S, E2>(self, context: S) -> Result<T, E2>
901    where
902        S: Into<String>,
903        E2: FromString,
904        E: Into<E2::Source>,
905    {
906        // https://github.com/rust-lang/rust/issues/74042
907        match self {
908            Ok(v) => Ok(v),
909            Err(error) => Err(FromString::with_source(error.into(), context.into())),
910        }
911    }
912
913    #[cfg(any(feature = "alloc", test))]
914    #[track_caller]
915    fn with_whatever_context<F, S, E2>(self, context: F) -> Result<T, E2>
916    where
917        F: FnOnce(&mut E) -> S,
918        S: Into<String>,
919        E2: FromString,
920        E: Into<E2::Source>,
921    {
922        // https://github.com/rust-lang/rust/issues/74042
923        match self {
924            Ok(t) => Ok(t),
925            Err(mut e) => {
926                let context = context(&mut e);
927                Err(FromString::with_source(e.into(), context.into()))
928            }
929        }
930    }
931
932    #[cfg(any(feature = "alloc", test))]
933    fn boxed<'a>(self) -> Result<T, Box<dyn Error + Send + Sync + 'a>>
934    where
935        E: Error + Send + Sync + 'a,
936    {
937        self.map_err(|e| Box::new(e) as _)
938    }
939
940    #[cfg(any(feature = "alloc", test))]
941    fn boxed_local<'a>(self) -> Result<T, Box<dyn Error + 'a>>
942    where
943        E: Error + 'a,
944    {
945        self.map_err(|e| Box::new(e) as _)
946    }
947}
948
949/// A temporary error type used when converting an [`Option`][] into a
950/// [`Result`][]
951///
952/// [`Option`]: std::option::Option
953/// [`Result`]: std::result::Result
954pub struct NoneError;
955
956/// Additions to [`Option`][].
957pub trait OptionExt<T>: Sized {
958    /// Convert an [`Option`][] into a [`Result`][] with additional
959    /// context-sensitive information.
960    ///
961    /// [Option]: std::option::Option
962    /// [Result]: std::result::Result
963    ///
964    /// ```rust
965    /// use snafu::prelude::*;
966    ///
967    /// #[derive(Debug, Snafu)]
968    /// enum Error {
969    ///     UserLookup { user_id: i32 },
970    /// }
971    ///
972    /// fn example(user_id: i32) -> Result<(), Error> {
973    ///     let name = username(user_id).context(UserLookupSnafu { user_id })?;
974    ///     println!("Username was {name}");
975    ///     Ok(())
976    /// }
977    ///
978    /// fn username(user_id: i32) -> Option<String> {
979    ///     /* ... */
980    /// # None
981    /// }
982    /// ```
983    ///
984    /// Note that the context selector will call [`Into::into`][] on each field,
985    /// so the types are not required to exactly match.
986    fn context<C, E>(self, context: C) -> Result<T, E>
987    where
988        C: IntoError<E, Source = NoneError>;
989
990    /// Convert an [`Option`][] into a [`Result`][] with
991    /// lazily-generated context-sensitive information.
992    ///
993    /// [`Option`]: std::option::Option
994    /// [`Result`]: std::result::Result
995    ///
996    /// ```
997    /// use snafu::prelude::*;
998    ///
999    /// #[derive(Debug, Snafu)]
1000    /// enum Error {
1001    ///     UserLookup {
1002    ///         user_id: i32,
1003    ///         previous_ids: Vec<i32>,
1004    ///     },
1005    /// }
1006    ///
1007    /// fn example(user_id: i32) -> Result<(), Error> {
1008    ///     let name = username(user_id).with_context(|| UserLookupSnafu {
1009    ///         user_id,
1010    ///         previous_ids: Vec::new(),
1011    ///     })?;
1012    ///     println!("Username was {name}");
1013    ///     Ok(())
1014    /// }
1015    ///
1016    /// fn username(user_id: i32) -> Option<String> {
1017    ///     /* ... */
1018    /// # None
1019    /// }
1020    /// ```
1021    ///
1022    /// Note that this *may not* be needed in many cases because the context
1023    /// selector will call [`Into::into`][] on each field.
1024    fn with_context<F, C, E>(self, context: F) -> Result<T, E>
1025    where
1026        F: FnOnce() -> C,
1027        C: IntoError<E, Source = NoneError>;
1028
1029    /// Convert an [`Option`] into a [`Result`] with information
1030    /// from a string.
1031    ///
1032    /// The target error type must implement [`FromString`] by using
1033    /// the
1034    /// [`#[snafu(whatever)]`][Snafu#controlling-stringly-typed-errors]
1035    /// attribute. The premade [`Whatever`] type is also available.
1036    ///
1037    /// In many cases, you will want to use
1038    /// [`with_whatever_context`][Self::with_whatever_context] instead
1039    /// as it is only called in case of error. This method is best
1040    /// suited for when you have a string literal.
1041    ///
1042    /// ```rust
1043    /// use snafu::{prelude::*, Whatever};
1044    ///
1045    /// fn example(env_var_name: &str) -> Result<(), Whatever> {
1046    ///     std::env::var_os(env_var_name).whatever_context("couldn't get the environment variable")?;
1047    ///     Ok(())
1048    /// }
1049    ///
1050    /// let err = example("UNDEFINED_ENVIRONMENT_VARIABLE").unwrap_err();
1051    /// assert_eq!("couldn't get the environment variable", err.to_string());
1052    /// ```
1053    #[cfg(any(feature = "alloc", test))]
1054    fn whatever_context<S, E>(self, context: S) -> Result<T, E>
1055    where
1056        S: Into<String>,
1057        E: FromString;
1058
1059    /// Convert an [`Option`] into a [`Result`][] with information from a
1060    /// lazily-generated string.
1061    ///
1062    /// The target error type must implement [`FromString`][] by using
1063    /// the
1064    /// [`#[snafu(whatever)]`][Snafu#controlling-stringly-typed-errors]
1065    /// attribute. The premade [`Whatever`][] type is also available.
1066    ///
1067    /// ```rust
1068    /// use snafu::{prelude::*, Whatever};
1069    ///
1070    /// fn example(env_var_name: &str) -> Result<(), Whatever> {
1071    ///     std::env::var_os(env_var_name).with_whatever_context(|| {
1072    ///         format!("couldn't get the environment variable {env_var_name}")
1073    ///     })?;
1074    ///     Ok(())
1075    /// }
1076    ///
1077    /// let err = example("UNDEFINED_ENVIRONMENT_VARIABLE").unwrap_err();
1078    /// assert_eq!(
1079    ///     "couldn't get the environment variable UNDEFINED_ENVIRONMENT_VARIABLE",
1080    ///     err.to_string()
1081    /// );
1082    /// ```
1083    ///
1084    /// The closure is not called when the `Option` is `Some`:
1085    ///
1086    /// ```rust
1087    /// use snafu::{prelude::*, Whatever};
1088    ///
1089    /// let value = Some(42);
1090    /// let result = value.with_whatever_context::<_, String, Whatever>(|| {
1091    ///     panic!("This block will not be evaluated");
1092    /// });
1093    ///
1094    /// assert!(result.is_ok());
1095    /// ```
1096    #[cfg(any(feature = "alloc", test))]
1097    fn with_whatever_context<F, S, E>(self, context: F) -> Result<T, E>
1098    where
1099        F: FnOnce() -> S,
1100        S: Into<String>,
1101        E: FromString;
1102}
1103
1104impl<T> OptionExt<T> for Option<T> {
1105    #[track_caller]
1106    fn context<C, E>(self, context: C) -> Result<T, E>
1107    where
1108        C: IntoError<E, Source = NoneError>,
1109    {
1110        // https://github.com/rust-lang/rust/issues/74042
1111        match self {
1112            Some(v) => Ok(v),
1113            None => Err(context.into_error(NoneError)),
1114        }
1115    }
1116
1117    #[track_caller]
1118    fn with_context<F, C, E>(self, context: F) -> Result<T, E>
1119    where
1120        F: FnOnce() -> C,
1121        C: IntoError<E, Source = NoneError>,
1122    {
1123        // https://github.com/rust-lang/rust/issues/74042
1124        match self {
1125            Some(v) => Ok(v),
1126            None => Err(context().into_error(NoneError)),
1127        }
1128    }
1129
1130    #[cfg(any(feature = "alloc", test))]
1131    #[track_caller]
1132    fn whatever_context<S, E>(self, context: S) -> Result<T, E>
1133    where
1134        S: Into<String>,
1135        E: FromString,
1136    {
1137        match self {
1138            Some(v) => Ok(v),
1139            None => Err(FromString::without_source(context.into())),
1140        }
1141    }
1142
1143    #[cfg(any(feature = "alloc", test))]
1144    #[track_caller]
1145    fn with_whatever_context<F, S, E>(self, context: F) -> Result<T, E>
1146    where
1147        F: FnOnce() -> S,
1148        S: Into<String>,
1149        E: FromString,
1150    {
1151        match self {
1152            Some(v) => Ok(v),
1153            None => {
1154                let context = context();
1155                Err(FromString::without_source(context.into()))
1156            }
1157        }
1158    }
1159}
1160
1161/// Backports changes to the [`Error`][] trait to versions of Rust
1162/// lacking them.
1163///
1164/// It is recommended to always call these methods explicitly so that
1165/// it is easy to replace usages of this trait when you start
1166/// supporting a newer version of Rust.
1167///
1168/// ```
1169/// # use snafu::{prelude::*, ErrorCompat};
1170/// # #[derive(Debug, Snafu)] enum Example {};
1171/// # fn example(error: Example) {
1172/// ErrorCompat::backtrace(&error); // Recommended
1173/// error.backtrace();              // Discouraged
1174/// # }
1175/// ```
1176///
1177/// This trait does not require [`Error`], [`core::fmt::Debug`], or
1178/// [`core::fmt::Display`]. Backtrace access and standard error-chain access
1179/// are separate capabilities; [`ErrorCompat::iter_chain`] additionally
1180/// requires [`AsErrorSource`].
1181pub trait ErrorCompat {
1182    /// Returns a [`Backtrace`][] that may be printed.
1183    fn backtrace(&self) -> Option<&Backtrace> {
1184        None
1185    }
1186
1187    /// Returns an iterator for traversing the chain of errors,
1188    /// starting with the current error
1189    /// and continuing with recursive calls to `Error::source`.
1190    ///
1191    /// To omit the current error and only traverse its sources,
1192    /// use `skip(1)`.
1193    fn iter_chain(&self) -> ChainCompat<'_, '_>
1194    where
1195        Self: AsErrorSource,
1196    {
1197        ChainCompat::new(self.as_error_source())
1198    }
1199}
1200
1201impl<'a, E> ErrorCompat for &'a E
1202where
1203    E: ErrorCompat,
1204{
1205    fn backtrace(&self) -> Option<&Backtrace> {
1206        (**self).backtrace()
1207    }
1208}
1209
1210/// Converts the receiver into an [`Error`][] trait object, suitable
1211/// for use in [`Error::source`][].
1212///
1213/// It is expected that most users of SNAFU will not directly interact
1214/// with this trait.
1215///
1216/// [`Error`]: std::error::Error
1217/// [`Error::source`]: std::error::Error::source
1218//
1219// Given an error enum with multiple types of underlying causes:
1220//
1221// ```rust
1222// enum Error {
1223//     BoxTraitObjectSendSync(Box<dyn error::Error + Send + Sync + 'static>),
1224//     BoxTraitObject(Box<dyn error::Error + 'static>),
1225//     Boxed(Box<io::Error>),
1226//     Unboxed(io::Error),
1227// }
1228// ```
1229//
1230// This trait provides the answer to what consistent expression can go
1231// in each match arm:
1232//
1233// ```rust
1234// impl error::Error for Error {
1235//     fn source(&self) -> Option<&(dyn error::Error + 'static)> {
1236//         use Error::*;
1237//
1238//         let v = match *self {
1239//             BoxTraitObjectSendSync(ref e) => ...,
1240//             BoxTraitObject(ref e) => ...,
1241//             Boxed(ref e) => ...,
1242//             Unboxed(ref e) => ...,
1243//         };
1244//
1245//         Some(v)
1246//     }
1247// }
1248//
1249// Existing methods like returning `e`, `&**e`, `Borrow::borrow(e)`,
1250// `Deref::deref(e)`, and `AsRef::as_ref(e)` do not work for various
1251// reasons.
1252pub trait AsErrorSource {
1253    /// For maximum effectiveness, this needs to be called as a method
1254    /// to benefit from Rust's automatic dereferencing of method
1255    /// receivers.
1256    fn as_error_source(&self) -> &(dyn Error + 'static);
1257}
1258
1259impl AsErrorSource for dyn Error + 'static {
1260    fn as_error_source(&self) -> &(dyn Error + 'static) {
1261        self
1262    }
1263}
1264
1265impl AsErrorSource for dyn Error + Send + 'static {
1266    fn as_error_source(&self) -> &(dyn Error + 'static) {
1267        self
1268    }
1269}
1270
1271impl AsErrorSource for dyn Error + Sync + 'static {
1272    fn as_error_source(&self) -> &(dyn Error + 'static) {
1273        self
1274    }
1275}
1276
1277impl AsErrorSource for dyn Error + Send + Sync + 'static {
1278    fn as_error_source(&self) -> &(dyn Error + 'static) {
1279        self
1280    }
1281}
1282
1283impl<T> AsErrorSource for T
1284where
1285    T: Error + 'static,
1286{
1287    fn as_error_source(&self) -> &(dyn Error + 'static) {
1288        self
1289    }
1290}
1291
1292/// Combines an underlying error with additional information
1293/// about the error.
1294///
1295/// It is expected that most users of SNAFU will not directly interact
1296/// with this trait.
1297///
1298/// Constructing `E` does not require it to implement
1299/// [`Error`] or [`ErrorCompat`]. Callers that report the result must add
1300/// the diagnostic bounds they use. A generated selector may still require
1301/// source capabilities for source-aware [`GenerateImplicitData`].
1302pub trait IntoError<E> {
1303    /// The underlying error
1304    type Source;
1305
1306    /// Combine the information to produce the error
1307    fn into_error(self, source: Self::Source) -> E;
1308}
1309
1310/// Takes a string message and builds the corresponding error.
1311///
1312/// It is expected that most users of SNAFU will not directly interact
1313/// with this trait.
1314#[cfg(any(feature = "alloc", test))]
1315pub trait FromString {
1316    /// The underlying error
1317    type Source;
1318
1319    /// Create a brand new error from the given string
1320    fn without_source(message: String) -> Self;
1321
1322    /// Wrap an existing error with the given string
1323    fn with_source(source: Self::Source, message: String) -> Self;
1324}
1325
1326/// Construct data to be included as part of an error. The data must
1327/// require no arguments to be created.
1328pub trait GenerateImplicitData {
1329    /// Build the data.
1330    fn generate() -> Self;
1331
1332    /// Build the data using the given source
1333    #[track_caller]
1334    fn generate_with_source(source: &dyn crate::Error) -> Self
1335    where
1336        Self: Sized,
1337    {
1338        let _source = source;
1339        Self::generate()
1340    }
1341}
1342
1343/// View a backtrace-like value as an optional backtrace.
1344pub trait AsBacktrace {
1345    /// Retrieve the optional backtrace
1346    fn as_backtrace(&self) -> Option<&Backtrace>;
1347}
1348
1349/// Only create a backtrace when an environment variable is set.
1350///
1351/// This looks first for the value of `RUST_LIB_BACKTRACE` then
1352/// `RUST_BACKTRACE`. If the value is set to `1`, backtraces will be
1353/// enabled.
1354///
1355/// This value will be tested only once per program execution;
1356/// changing the environment variable after it has been checked will
1357/// have no effect.
1358///
1359/// ## Interaction with the Provider API
1360///
1361/// If you enable the [`unstable-provider-api` feature
1362/// flag][provider-ff], a backtrace will not be captured if the
1363/// original error is able to provide a `Backtrace`, even if the
1364/// appropriate environment variables are set. This prevents capturing
1365/// a redundant backtrace.
1366///
1367/// [provider-ff]: crate::guide::feature_flags#unstable-provider-api
1368#[cfg(any(feature = "std", test))]
1369impl GenerateImplicitData for Option<Backtrace> {
1370    fn generate() -> Self {
1371        if backtrace_collection_enabled() {
1372            Some(Backtrace::generate())
1373        } else {
1374            None
1375        }
1376    }
1377
1378    fn generate_with_source(source: &dyn crate::Error) -> Self {
1379        #[cfg(feature = "unstable-provider-api")]
1380        {
1381            if !backtrace_collection_enabled() {
1382                None
1383            } else if backtraces(source).next().is_some() {
1384                None
1385            } else {
1386                Some(Backtrace::generate_with_source(source))
1387            }
1388        }
1389
1390        #[cfg(not(feature = "unstable-provider-api"))]
1391        {
1392            let _source = source;
1393            Self::generate()
1394        }
1395    }
1396}
1397
1398#[cfg(any(feature = "std", test))]
1399impl AsBacktrace for Option<Backtrace> {
1400    fn as_backtrace(&self) -> Option<&Backtrace> {
1401        self.as_ref()
1402    }
1403}
1404
1405#[cfg(any(feature = "std", test))]
1406fn backtrace_collection_enabled() -> bool {
1407    use crate::once_bool::OnceBool;
1408    use std::env;
1409
1410    static ENABLED: OnceBool = OnceBool::new();
1411
1412    ENABLED.get(|| {
1413        // TODO: What values count as "true"?
1414        env::var_os("RUST_LIB_BACKTRACE")
1415            .or_else(|| env::var_os("RUST_BACKTRACE"))
1416            .map_or(false, |v| v == "1")
1417    })
1418}
1419
1420/// The source code location where the error was reported.
1421///
1422/// To use it, add a field of type `Location` to your error and
1423/// register it as [implicitly generated data][implicit]. When
1424/// constructing the error, you do not need to provide the location:
1425///
1426/// ```rust
1427/// # use snafu::prelude::*;
1428/// #[derive(Debug, Snafu)]
1429/// struct NeighborhoodError {
1430///     #[snafu(implicit)]
1431///     loc: snafu::Location,
1432/// }
1433///
1434/// fn check_next_door() -> Result<(), NeighborhoodError> {
1435///     ensure!(everything_quiet(), NeighborhoodSnafu);
1436///     Ok(())
1437/// }
1438/// # fn everything_quiet() -> bool { false }
1439/// ```
1440///
1441/// [implicit]: Snafu#controlling-implicitly-generated-data
1442///
1443/// ## Limitations
1444///
1445/// Implicitly generated data, including `Location`, is generated when
1446/// the wrapping error value is constructed:
1447///
1448/// ```rust
1449/// # use snafu::{prelude::*, Location, location};
1450/// # fn fallible_code() -> Result<(), InnerError> { Err(InnerError) }
1451/// # #[derive(Debug, Snafu)] struct InnerError;
1452/// # #[derive(Debug, Snafu)]
1453/// # struct InterestingError {
1454/// #   source: InnerError,
1455/// #   #[snafu(implicit)] location: Location,
1456/// # }
1457/// # let base_loc = location!();
1458/// # let r: Result<(), InterestingError> = (|| {
1459/// // The first we know about the error is on this line:
1460/// let e = fallible_code();
1461/// // but the location will correspond to this line:
1462/// e.context(InterestingSnafu)?;
1463/// # Ok(())
1464/// # })();
1465/// # let e = r.unwrap_err();
1466/// # assert_eq!(e.location.line(), base_loc.line() + 5);
1467/// ```
1468///
1469/// If you have [disabled the context selector][disabled], the
1470/// `Location` will correspond to where the `From` implementation is
1471/// invoked. This is usually part of the `?` operator:
1472///
1473/// ```rust
1474/// # use snafu::{prelude::*, Location, location};
1475/// # fn fallible_code() -> Result<(), InnerError> { Err(InnerError) }
1476/// # #[derive(Debug, Snafu)] struct InnerError;
1477/// # #[derive(Debug, Snafu)]
1478/// # #[snafu(context(false))]
1479/// # struct InterestingError {
1480/// #   source: InnerError,
1481/// #   #[snafu(implicit)] location: Location,
1482/// # }
1483/// # let base_loc = location!();
1484/// # let r: Result<(), InterestingError> = (|| {
1485/// // The first we know about the error is on this line:
1486/// let e = fallible_code();
1487/// // but the location will correspond to this line:
1488/// e?;
1489/// # Ok(())
1490/// # })();
1491/// # let e = r.unwrap_err();
1492/// # assert_eq!(e.location.line(), base_loc.line() + 5);
1493/// ```
1494///
1495/// Inspecting the code at the generated `Location` will usually
1496/// quickly lead back to the original error, but it's recommended to
1497/// create the wrapping error as close to the original error location
1498/// to reduce confusion.
1499///
1500/// [disabled]: Snafu#disabling-the-context-selector
1501///
1502/// ### Asynchronous code
1503///
1504/// When using SNAFU's
1505#[cfg_attr(feature = "futures", doc = " [`TryFutureExt`][futures::TryFutureExt]")]
1506#[cfg_attr(not(feature = "futures"), doc = " `TryFutureExt`")]
1507/// or
1508#[cfg_attr(feature = "futures", doc = " [`TryStreamExt`][futures::TryStreamExt]")]
1509#[cfg_attr(not(feature = "futures"), doc = " `TryStreamExt`")]
1510/// extension traits, the automatically captured location will
1511/// correspond to where the future or stream was **polled**, not where
1512/// it was created. Additionally, many `Future` or `Stream`
1513/// combinators do not forward the caller's location to their
1514/// closures, causing the recorded location to be inside of the future
1515/// combinator's library.
1516///
1517/// There are two workarounds:
1518/// 1. Avoid combinators and use the non-async [`ResultExt`]
1519/// 1. Construct the location explicitly, such as by the [`location!`] macro
1520///
1521/// ```rust
1522/// # #[cfg(all(feature = "futures", feature = "internal-dev-dependencies"))] {
1523/// # use snafu::{prelude::*, Location, location};
1524/// # let body = async {
1525/// // Non-ideal: will report where `wrapped_error_future` is `.await`ed.
1526/// # let base_location = location!();
1527/// # let error_future = async { AnotherSnafu.fail::<()>() };
1528/// let wrapped_error_future = error_future.context(ImplicitLocationSnafu);
1529/// # let wrapped_error = wrapped_error_future.await.unwrap_err();
1530/// # assert_eq!(wrapped_error.location.line(), base_location.line() + 3);
1531///
1532/// // Better: will report the location of `.context`.
1533/// # let base_location = location!();
1534/// # let error_future = async { AnotherSnafu.fail::<()>() };
1535/// let wrapped_error_future = async { error_future.await.context(ImplicitLocationSnafu) };
1536/// # let wrapped_error = wrapped_error_future.await.unwrap_err();
1537/// # assert_eq!(wrapped_error.location.line(), base_location.line() + 2);
1538///
1539/// // Better: Will report the location of `location!`
1540/// # let base_location = location!();
1541/// # let error_future = async { AnotherSnafu.fail::<()>() };
1542/// let wrapped_error_future = error_future.with_context(|_| ExplicitLocationSnafu {
1543///     location: location!(),
1544/// });
1545/// # let wrapped_error = wrapped_error_future.await.unwrap_err();
1546/// # assert_eq!(wrapped_error.location.line(), base_location.line() + 3);
1547///
1548/// # #[derive(Debug, Snafu)] struct AnotherError;
1549/// #[derive(Debug, Snafu)]
1550/// struct ImplicitLocationError {
1551///     source: AnotherError,
1552///     #[snafu(implicit)]
1553///     location: snafu::Location,
1554/// }
1555///
1556/// #[derive(Debug, Snafu)]
1557/// struct ExplicitLocationError {
1558///     source: AnotherError,
1559///     location: snafu::Location,
1560/// }
1561/// # };
1562/// # futures::executor::block_on(body);
1563/// # }
1564/// ```
1565pub type Location = &'static core::panic::Location<'static>;
1566
1567impl GenerateImplicitData for Location {
1568    #[inline]
1569    #[track_caller]
1570    fn generate() -> Self {
1571        core::panic::Location::caller()
1572    }
1573}
1574
1575/// Constructs a [`Location`] using the current file, line, and column.
1576#[macro_export]
1577macro_rules! location {
1578    () => {
1579        core::panic::Location::caller()
1580    };
1581}
1582
1583#[cfg(feature = "unstable-provider-api")]
1584fn backtraces(error: &dyn Error) -> impl Iterator<Item = &Backtrace> {
1585    ChainCompat::new(error).filter_map(error::request_ref)
1586}
1587
1588mod tests {
1589    #[cfg(doc)]
1590    #[doc = include_str!("../README.md")]
1591    fn readme_tests() {}
1592}