#![deny(missing_docs)]
#![allow(stable_features)]
#![cfg_attr(docsrs, feature(doc_cfg))]
#![no_std]
#![cfg_attr(
feature = "unstable-provider-api",
feature(error_generic_member_access)
)]
#![cfg_attr(feature = "unstable-try-trait", feature(try_trait_v2))]
#")]
#")]
#[cfg(feature = "alloc")]
extern crate alloc;
#[cfg(feature = "alloc")]
use alloc::{boxed::Box, string::String};
#[cfg(feature = "std")]
extern crate std;
pub mod prelude {
pub use crate::{ensure, OptionExt as _, ResultExt as _};
#[doc = include_str!("Snafu.md")]
#[allow(rustdoc::broken_intra_doc_links)]
pub use snafu_derive::Snafu;
#[cfg(any(feature = "alloc", test))]
pub use crate::{ensure_whatever, whatever};
#[cfg(feature = "futures")]
pub use crate::futures::{TryFutureExt as _, TryStreamExt as _};
}
#[cfg(not(any(feature = "std", feature = "backtraces-impl-backtrace-crate")))]
#[path = "backtrace_impl_inert.rs"]
mod backtrace_impl;
#[cfg(feature = "backtraces-impl-backtrace-crate")]
#[path = "backtrace_impl_backtrace_crate.rs"]
mod backtrace_impl;
#[cfg(all(feature = "std", not(feature = "backtraces-impl-backtrace-crate")))]
#[path = "backtrace_impl_std.rs"]
mod backtrace_impl;
pub use backtrace_impl::*;
#[cfg(any(feature = "std", test))]
mod once_bool;
#[cfg(feature = "futures")]
pub mod futures;
mod error_chain;
pub use crate::error_chain::*;
mod report;
#[cfg(feature = "alloc")]
pub use report::CleanedErrorText;
pub use report::{__InternalExtractErrorType, Report};
#[doc = include_str!("Snafu.md")]
#[doc(alias(
"backtrace",
"context",
"crate_root",
"display",
"implicit",
"module",
"provide",
"source",
"transparent",
"visibility",
"whatever",
))]
pub use snafu_derive::Snafu;
#[doc = include_str!("report.md")]
pub use snafu_derive::report;
macro_rules! generate_guide {
(pub mod $name:ident { $($children:tt)* } $($rest:tt)*) => {
generate_guide!(@gen ".", pub mod $name { $($children)* } $($rest)*);
};
(@gen $prefix:expr, ) => {};
(@gen $prefix:expr, pub mod $name:ident; $($rest:tt)*) => {
generate_guide!(@gen $prefix, pub mod $name { } $($rest)*);
};
(@gen $prefix:expr, @code pub mod $name:ident; $($rest:tt)*) => {
#[cfg(feature = "guide")]
pub mod $name;
#[cfg(not(feature = "guide"))]
pub mod $name {}
generate_guide!(@gen $prefix, $($rest)*);
};
(@gen $prefix:expr, pub mod $name:ident { $($children:tt)* } $($rest:tt)*) => {
#[cfg(feature = "guide")]
#[doc = include_str!(concat!($prefix, "/", stringify!($name), ".md"))]
pub mod $name {
use crate::*;
generate_guide!(@gen concat!($prefix, "/", stringify!($name)), $($children)*);
}
#[cfg(not(feature = "guide"))]
pub mod $name {
generate_guide!(@gen concat!($prefix, "/", stringify!($name)), $($children)*);
}
generate_guide!(@gen $prefix, $($rest)*);
};
}
generate_guide! {
pub mod guide {
pub mod comparison {
pub mod failure;
}
pub mod compatibility;
pub mod feature_flags;
pub mod generics;
pub mod opaque;
pub mod philosophy;
pub mod structs;
pub mod what_code_is_generated;
pub mod troubleshooting {
pub mod missing_field_source;
}
pub mod upgrading;
@code pub mod examples;
}
}
#[cfg(feature = "rust_1_81")]
#[doc(hidden)]
pub use core::error;
#[cfg(feature = "rust_1_81")]
#[doc(hidden)]
pub use core::error::Error;
#[cfg(all(not(feature = "rust_1_81"), any(feature = "std", test)))]
#[doc(hidden)]
pub use std::error;
#[cfg(all(not(feature = "rust_1_81"), any(feature = "std", test)))]
#[doc(hidden)]
pub use std::error::Error;
#[cfg(not(any(feature = "rust_1_81", feature = "std", test)))]
mod fallback_error;
#[cfg(not(any(feature = "rust_1_81", feature = "std", test)))]
#[doc(hidden)]
pub use fallback_error::Error;
#[cfg(any(feature = "alloc", test))]
mod boxed_impls;
#[cfg(any(feature = "alloc", test))]
mod whatever;
#[cfg(any(feature = "alloc", test))]
pub use whatever::*;
#[macro_export]
macro_rules! ensure {
($predicate:expr, $context_selector:expr $(,)?) => {
if !$predicate {
return $context_selector
.fail()
.map_err(::core::convert::Into::into);
}
};
}
#[cfg(feature = "alloc")]
#[doc(hidden)]
pub use alloc::format as __format;
#[macro_export]
#[cfg(any(feature = "alloc", test))]
macro_rules! whatever {
($fmt:literal$(, $($arg:expr),* $(,)?)?) => {
return core::result::Result::Err({
$crate::FromString::without_source(
$crate::__format!($fmt$(, $($arg),*)*),
)
})
};
($source:expr, $fmt:literal$(, $($arg:expr),* $(,)?)*) => {
match $source {
core::result::Result::Ok(v) => v,
core::result::Result::Err(e) => {
return core::result::Result::Err({
$crate::FromString::with_source(
core::convert::Into::into(e),
$crate::__format!($fmt$(, $($arg),*)*),
)
});
}
}
};
}
#[macro_export]
#[cfg(any(feature = "alloc", test))]
macro_rules! ensure_whatever {
($predicate:expr, $fmt:literal$(, $($arg:expr),* $(,)?)?) => {
if !$predicate {
$crate::whatever!($fmt$(, $($arg),*)*);
}
};
}
pub trait ResultExt<T, E>: Sized {
fn context<C, E2>(self, context: C) -> Result<T, E2>
where
C: IntoError<E2, Source = E>,
E2: Error + ErrorCompat;
fn with_context<F, C, E2>(self, context: F) -> Result<T, E2>
where
F: FnOnce(&mut E) -> C,
C: IntoError<E2, Source = E>,
E2: Error + ErrorCompat;
#[cfg(any(feature = "alloc", test))]
fn whatever_context<S, E2>(self, context: S) -> Result<T, E2>
where
S: Into<String>,
E2: FromString,
E: Into<E2::Source>;
#[cfg(any(feature = "alloc", test))]
fn with_whatever_context<F, S, E2>(self, context: F) -> Result<T, E2>
where
F: FnOnce(&mut E) -> S,
S: Into<String>,
E2: FromString,
E: Into<E2::Source>;
#[cfg(any(feature = "alloc", test))]
fn boxed<'a>(self) -> Result<T, Box<dyn Error + Send + Sync + 'a>>
where
E: Error + Send + Sync + 'a;
#[cfg(any(feature = "alloc", test))]
fn boxed_local<'a>(self) -> Result<T, Box<dyn Error + 'a>>
where
E: Error + 'a;
}
impl<T, E> ResultExt<T, E> for Result<T, E> {
#[track_caller]
fn context<C, E2>(self, context: C) -> Result<T, E2>
where
C: IntoError<E2, Source = E>,
E2: Error + ErrorCompat,
{
match self {
Ok(v) => Ok(v),
Err(error) => Err(context.into_error(error)),
}
}
#[track_caller]
fn with_context<F, C, E2>(self, context: F) -> Result<T, E2>
where
F: FnOnce(&mut E) -> C,
C: IntoError<E2, Source = E>,
E2: Error + ErrorCompat,
{
match self {
Ok(v) => Ok(v),
Err(mut error) => {
let context = context(&mut error);
Err(context.into_error(error))
}
}
}
#[cfg(any(feature = "alloc", test))]
#[track_caller]
fn whatever_context<S, E2>(self, context: S) -> Result<T, E2>
where
S: Into<String>,
E2: FromString,
E: Into<E2::Source>,
{
match self {
Ok(v) => Ok(v),
Err(error) => Err(FromString::with_source(error.into(), context.into())),
}
}
#[cfg(any(feature = "alloc", test))]
#[track_caller]
fn with_whatever_context<F, S, E2>(self, context: F) -> Result<T, E2>
where
F: FnOnce(&mut E) -> S,
S: Into<String>,
E2: FromString,
E: Into<E2::Source>,
{
match self {
Ok(t) => Ok(t),
Err(mut e) => {
let context = context(&mut e);
Err(FromString::with_source(e.into(), context.into()))
}
}
}
#[cfg(any(feature = "alloc", test))]
fn boxed<'a>(self) -> Result<T, Box<dyn Error + Send + Sync + 'a>>
where
E: Error + Send + Sync + 'a,
{
self.map_err(|e| Box::new(e) as _)
}
#[cfg(any(feature = "alloc", test))]
fn boxed_local<'a>(self) -> Result<T, Box<dyn Error + 'a>>
where
E: Error + 'a,
{
self.map_err(|e| Box::new(e) as _)
}
}
pub struct NoneError;
pub trait OptionExt<T>: Sized {
fn context<C, E>(self, context: C) -> Result<T, E>
where
C: IntoError<E, Source = NoneError>,
E: Error + ErrorCompat;
fn with_context<F, C, E>(self, context: F) -> Result<T, E>
where
F: FnOnce() -> C,
C: IntoError<E, Source = NoneError>,
E: Error + ErrorCompat;
#[cfg(any(feature = "alloc", test))]
fn whatever_context<S, E>(self, context: S) -> Result<T, E>
where
S: Into<String>,
E: FromString;
#[cfg(any(feature = "alloc", test))]
fn with_whatever_context<F, S, E>(self, context: F) -> Result<T, E>
where
F: FnOnce() -> S,
S: Into<String>,
E: FromString;
}
impl<T> OptionExt<T> for Option<T> {
#[track_caller]
fn context<C, E>(self, context: C) -> Result<T, E>
where
C: IntoError<E, Source = NoneError>,
E: Error + ErrorCompat,
{
match self {
Some(v) => Ok(v),
None => Err(context.into_error(NoneError)),
}
}
#[track_caller]
fn with_context<F, C, E>(self, context: F) -> Result<T, E>
where
F: FnOnce() -> C,
C: IntoError<E, Source = NoneError>,
E: Error + ErrorCompat,
{
match self {
Some(v) => Ok(v),
None => Err(context().into_error(NoneError)),
}
}
#[cfg(any(feature = "alloc", test))]
#[track_caller]
fn whatever_context<S, E>(self, context: S) -> Result<T, E>
where
S: Into<String>,
E: FromString,
{
match self {
Some(v) => Ok(v),
None => Err(FromString::without_source(context.into())),
}
}
#[cfg(any(feature = "alloc", test))]
#[track_caller]
fn with_whatever_context<F, S, E>(self, context: F) -> Result<T, E>
where
F: FnOnce() -> S,
S: Into<String>,
E: FromString,
{
match self {
Some(v) => Ok(v),
None => {
let context = context();
Err(FromString::without_source(context.into()))
}
}
}
}
pub trait ErrorCompat {
fn backtrace(&self) -> Option<&Backtrace> {
None
}
fn iter_chain(&self) -> ChainCompat<'_, '_>
where
Self: AsErrorSource,
{
ChainCompat::new(self.as_error_source())
}
}
impl<'a, E> ErrorCompat for &'a E
where
E: ErrorCompat,
{
fn backtrace(&self) -> Option<&Backtrace> {
(**self).backtrace()
}
}
pub trait AsErrorSource {
fn as_error_source(&self) -> &(dyn Error + 'static);
}
impl AsErrorSource for dyn Error + 'static {
fn as_error_source(&self) -> &(dyn Error + 'static) {
self
}
}
impl AsErrorSource for dyn Error + Send + 'static {
fn as_error_source(&self) -> &(dyn Error + 'static) {
self
}
}
impl AsErrorSource for dyn Error + Sync + 'static {
fn as_error_source(&self) -> &(dyn Error + 'static) {
self
}
}
impl AsErrorSource for dyn Error + Send + Sync + 'static {
fn as_error_source(&self) -> &(dyn Error + 'static) {
self
}
}
impl<T> AsErrorSource for T
where
T: Error + 'static,
{
fn as_error_source(&self) -> &(dyn Error + 'static) {
self
}
}
pub trait IntoError<E>
where
E: Error + ErrorCompat,
{
type Source;
fn into_error(self, source: Self::Source) -> E;
}
#[cfg(any(feature = "alloc", test))]
pub trait FromString {
type Source;
fn without_source(message: String) -> Self;
fn with_source(source: Self::Source, message: String) -> Self;
}
pub trait GenerateImplicitData {
fn generate() -> Self;
#[track_caller]
fn generate_with_source(source: &dyn crate::Error) -> Self
where
Self: Sized,
{
let _source = source;
Self::generate()
}
}
pub trait AsBacktrace {
fn as_backtrace(&self) -> Option<&Backtrace>;
}
#[cfg(any(feature = "std", test))]
impl GenerateImplicitData for Option<Backtrace> {
fn generate() -> Self {
if backtrace_collection_enabled() {
Some(Backtrace::generate())
} else {
None
}
}
fn generate_with_source(source: &dyn crate::Error) -> Self {
#[cfg(feature = "unstable-provider-api")]
{
if !backtrace_collection_enabled() {
None
} else if backtraces(source).next().is_some() {
None
} else {
Some(Backtrace::generate_with_source(source))
}
}
#[cfg(not(feature = "unstable-provider-api"))]
{
let _source = source;
Self::generate()
}
}
}
#[cfg(any(feature = "std", test))]
impl AsBacktrace for Option<Backtrace> {
fn as_backtrace(&self) -> Option<&Backtrace> {
self.as_ref()
}
}
#[cfg(any(feature = "std", test))]
fn backtrace_collection_enabled() -> bool {
use crate::once_bool::OnceBool;
use std::env;
static ENABLED: OnceBool = OnceBool::new();
ENABLED.get(|| {
env::var_os("RUST_LIB_BACKTRACE")
.or_else(|| env::var_os("RUST_BACKTRACE"))
.map_or(false, |v| v == "1")
})
}
#[cfg_attr(feature = "futures", doc = " [`TryFutureExt`][futures::TryFutureExt]")]
#[cfg_attr(not(feature = "futures"), doc = " `TryFutureExt`")]
#[cfg_attr(feature = "futures", doc = " [`TryStreamExt`][futures::TryStreamExt]")]
#[cfg_attr(not(feature = "futures"), doc = " `TryStreamExt`")]
pub type Location = &'static core::panic::Location<'static>;
impl GenerateImplicitData for Location {
#[inline]
#[track_caller]
fn generate() -> Self {
core::panic::Location::caller()
}
}
#[macro_export]
macro_rules! location {
() => {
core::panic::Location::caller()
};
}
#[cfg(feature = "unstable-provider-api")]
fn backtraces(error: &dyn Error) -> impl Iterator<Item = &Backtrace> {
ChainCompat::new(error).filter_map(error::request_ref)
}
mod tests {
#[cfg(doc)]
#[doc = include_str!("../README.md")]
fn readme_tests() {}
}