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#")]
30#")]
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}