use std::borrow::Cow;
use std::env;
use std::ffi;
use std::fmt;
use std::result;
use std::sync::atomic;
const RUST_BACKTRACE: &str = "RUST_BACKTRACE";
#[cfg(all(feature = "backtrace", feature = "std"))]
mod internal {
pub const HAS_BACKTRACE: bool = true;
pub use backtrace::Backtrace;
}
#[cfg(not(all(feature = "backtrace", feature = "std")))]
mod internal {
pub const HAS_BACKTRACE: bool = false;
use std::fmt;
pub struct Backtrace(());
impl Backtrace {
pub fn new() -> Backtrace {
Backtrace(())
}
}
impl fmt::Debug for Backtrace {
fn fmt(&self, _fmt: &mut fmt::Formatter) -> fmt::Result {
Ok(())
}
}
}
pub use self::internal::{Backtrace, HAS_BACKTRACE};
pub type Result<T> = result::Result<T, Error>;
pub trait ResultExt<T>
where
Self: Sized,
{
fn chain_err<C, D>(self, chain: C) -> Result<T>
where
C: FnOnce() -> D,
D: Into<Error>;
}
impl<T> ResultExt<T> for result::Result<T, Error> {
fn chain_err<C, D>(self, chain: C) -> Result<T>
where
C: FnOnce() -> D,
D: Into<Error>,
{
match self {
Err(e) => {
let mut new = chain().into();
new.cause = Some(Box::new(e));
Err(new)
}
Ok(value) => Ok(value),
}
}
}
#[derive(Debug, Clone)]
pub struct Causes<'a> {
current: Option<&'a Error>,
}
impl<'a> Iterator for Causes<'a> {
type Item = &'a Error;
fn next(&mut self) -> Option<Self::Item> {
if let Some(e) = self.current {
self.current = e.cause();
return Some(e);
}
None
}
}
pub struct Display<'a> {
message: Cow<'a, str>,
}
impl<'a> fmt::Display for Display<'a> {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.write_str(self.message.as_ref())
}
}
fn is_backtrace_enabled<F: Fn(&str) -> Option<ffi::OsString>>(get_var: F) -> bool {
match get_var(RUST_BACKTRACE) {
Some(ref val) if val != "0" => true,
_ => false,
}
}
pub struct Error {
message: Cow<'static, str>,
cause: Option<Box<Error>>,
suppressed: Vec<Error>,
backtrace: Option<Backtrace>,
}
impl Error {
pub fn new<M: Into<Cow<'static, str>>>(message: M) -> Self {
Self {
message: message.into(),
cause: None,
suppressed: Vec::new(),
backtrace: Self::new_backtrace(),
}
}
fn new_backtrace() -> Option<Backtrace> {
if !HAS_BACKTRACE {
return None;
}
static ENABLED: atomic::AtomicUsize = atomic::ATOMIC_USIZE_INIT;
match ENABLED.load(atomic::Ordering::SeqCst) {
0 => {
let enabled = is_backtrace_enabled(|var| env::var_os(var));
ENABLED.store(enabled as usize + 1, atomic::Ordering::SeqCst);
if !enabled {
return None;
}
}
1 => return None,
_ => {}
}
return Some(Backtrace::new());
}
pub fn with_suppressed<S: IntoIterator<Item = Error>>(self, suppressed: S) -> Error {
Error {
suppressed: suppressed.into_iter().collect(),
..self
}
}
pub fn display(&self) -> Display {
Display {
message: Cow::from(self.message.as_ref()),
}
}
pub fn backtrace(&self) -> Option<&Backtrace> {
self.backtrace.as_ref()
}
pub fn message(&self) -> &str {
self.message.as_ref()
}
pub fn cause(&self) -> Option<&Error> {
self.cause.as_ref().map(AsRef::as_ref)
}
pub fn suppressed(&self) -> Vec<&Error> {
self.suppressed.iter().collect()
}
pub fn causes(&self) -> Causes {
Causes {
current: Some(self),
}
}
}
impl<T> From<T> for Error
where
T: fmt::Display,
{
fn from(value: T) -> Error {
Error::new(value.to_string())
}
}
impl fmt::Debug for Error {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.debug_struct("Error")
.field("message", &self.message)
.finish()
}
}