snafu/
lib.rs

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