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