#![deny(missing_docs)]
#![allow(stable_features)]
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
#![cfg_attr(not(any(feature = "std", test)), no_std)]
#![cfg_attr(feature = "unstable-core-error", feature(error_in_core))]
#![cfg_attr(
feature = "unstable-provider-api",
feature(error_generic_member_access)
)]
#![cfg_attr(feature = "unstable-try-trait", feature(try_trait_v2))]
#")]
#")]
use core::fmt;
#[cfg(feature = "alloc")]
extern crate alloc;
#[cfg(feature = "alloc")]
use alloc::{boxed::Box, string::String};
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(
all(feature = "std", feature = "rust_1_65"),
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",
feature = "rust_1_65",
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::{Report, __InternalExtractErrorType};
#[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(any(feature = "rust_1_81", feature = "unstable-core-error"))]
#[doc(hidden)]
pub use core::error;
#[cfg(any(feature = "rust_1_81", feature = "unstable-core-error"))]
#[doc(hidden)]
pub use core::error::Error;
#[cfg(all(
not(any(feature = "rust_1_81", feature = "unstable-core-error")),
any(feature = "std", test)
))]
#[doc(hidden)]
pub use std::error;
#[cfg(all(
not(any(feature = "rust_1_81", feature = "unstable-core-error")),
any(feature = "std", test)
))]
#[doc(hidden)]
pub use std::error::Error;
#[cfg(not(any(
feature = "rust_1_81",
feature = "unstable-core-error",
feature = "std",
test
)))]
mod fallback_error;
#[cfg(not(any(
feature = "rust_1_81",
feature = "unstable-core-error",
feature = "std",
test
)))]
#[doc(hidden)]
pub use fallback_error::Error;
#[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()
}
}
#[cfg(any(feature = "alloc", test))]
impl<E> ErrorCompat for Box<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 error::request_ref::<Backtrace>(source).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`")]
#[derive(Copy, Clone)]
#[non_exhaustive]
pub struct Location {
pub file: &'static str,
pub line: u32,
pub column: u32,
}
impl Location {
pub fn new(file: &'static str, line: u32, column: u32) -> Self {
Self { file, line, column }
}
}
impl Default for Location {
#[track_caller]
fn default() -> Self {
let loc = core::panic::Location::caller();
Self {
file: loc.file(),
line: loc.line(),
column: loc.column(),
}
}
}
impl GenerateImplicitData for Location {
#[inline]
#[track_caller]
fn generate() -> Self {
Self::default()
}
}
impl fmt::Debug for Location {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Location")
.field("file", &self.file)
.field("line", &self.line)
.field("column", &self.column)
.finish()
}
}
impl fmt::Display for Location {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"{file}:{line}:{column}",
file = self.file,
line = self.line,
column = self.column,
)
}
}
#[macro_export]
macro_rules! location {
() => {
$crate::Location::new(file!(), line!(), column!())
};
}
#[derive(Debug, Snafu)]
#[snafu(crate_root(crate))]
#[snafu(whatever)]
#[snafu(display("{message}"))]
#[snafu(provide(opt, ref, chain, dyn std::error::Error => source.as_deref()))]
#[cfg(any(feature = "alloc", test))]
pub struct Whatever {
#[snafu(source(from(Box<dyn crate::Error>, Some)))]
#[snafu(provide(false))]
source: Option<Box<dyn crate::Error>>,
message: String,
backtrace: Backtrace,
}
#[cfg(any(feature = "alloc", test))]
impl Whatever {
pub fn backtrace(&self) -> Option<&Backtrace> {
let mut best_backtrace = &self.backtrace;
let mut source = self.source();
while let Some(s) = source {
if let Some(this) = s.downcast_ref::<Self>() {
best_backtrace = &this.backtrace;
}
source = s.source();
}
Some(best_backtrace)
}
}
mod tests {
#[cfg(doc)]
#[doc = include_str!("../README.md")]
fn readme_tests() {}
}