snafu/
lib.rs

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