Skip to content
This repository was archived by the owner on Aug 16, 2021. It is now read-only.

[WIP] Core support #64

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,9 @@ repository = "https://github.com/brson/error-chain"
license = "MIT/Apache-2.0"

[features]
default = ["backtrace", "example_generated"]
default = ["backtrace", "example_generated", "alloc"]
example_generated = []
alloc = []

[dependencies]
backtrace = { version = "0.3", optional = true }
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
54 changes: 35 additions & 19 deletions src/error_chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ macro_rules! error_chain_processed {
$( $rest )*
}
/// Convenient wrapper around `std::Result`.
pub type $result_name<T> = ::std::result::Result<T, $error_name>;
pub type $result_name<T> = $crate::Result<T, $error_name>;
};
// Without `Result` wrapper.
(
Expand Down Expand Up @@ -109,13 +109,13 @@ macro_rules! error_chain_processed {
}
}

impl ::std::error::Error for $error_name {
impl $crate::Error for $error_name {
fn description(&self) -> &str {
self.kind.description()
}

fn cause(&self) -> Option<&::std::error::Error> {
match self.state.next_error {
fn cause(&self) -> Option<&$crate::Error> {
match self.state.next_error() {
Some(ref c) => Some(&**c),
None => {
match self.kind {
Expand All @@ -132,11 +132,7 @@ macro_rules! error_chain_processed {
}
}

impl ::std::fmt::Display for $error_name {
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
::std::fmt::Display::fmt(&self.kind, f)
}
}
if_alloc!($error_name $error_kind_name);

$(
$(#[$meta_links])*
Expand Down Expand Up @@ -179,14 +175,6 @@ macro_rules! error_chain_processed {
}
}

impl ::std::ops::Deref for $error_name {
type Target = $error_kind_name;

fn deref(&self) -> &Self::Target {
&self.kind
}
}


// The ErrorKind type
// --------------
Expand All @@ -213,7 +201,7 @@ macro_rules! error_chain_processed {
$(
$(#[$meta_foreign_links])*
$foreign_link_variant(err: $foreign_link_error_path) {
description(::std::error::Error::description(err))
description($crate::Error::description(err))
display("{}", err)
}
) *
Expand Down Expand Up @@ -329,7 +317,7 @@ macro_rules! impl_extract_backtrace {
($error_name: ident
$error_kind_name: ident
$([$link_error_path: path, $(#[$meta_links: meta])*])*) => {
fn extract_backtrace(e: &(::std::error::Error + Send + 'static))
fn extract_backtrace(e: &($crate::Error + Send + 'static))
-> Option<Option<::std::sync::Arc<$crate::Backtrace>>> {
if let Some(e) = e.downcast_ref::<$error_name>() {
return Some(e.state.backtrace.clone());
Expand Down Expand Up @@ -360,3 +348,31 @@ macro_rules! impl_extract_backtrace {
$error_kind_name: ident
$([$link_error_path: path, $(#[$meta_links: meta])*])*) => {}
}

#[macro_export]
#[doc(hidden)]
#[cfg(feature = "alloc")]
macro_rules! if_alloc {
($error_name:ident $error_kind_name: ident) => {
impl ::std::fmt::Display for $error_name {
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
::std::fmt::Display::fmt(&self.kind, f)
}
}

impl ::std::ops::Deref for $error_name {
type Target = $error_kind_name;

fn deref(&self) -> &Self::Target {
&self.kind
}
}
}
}

#[macro_export]
#[doc(hidden)]
#[cfg(not(feature = "alloc"))]
macro_rules! if_alloc {
($error_name:ident $error_kind_name: ident) => {}
}
63 changes: 48 additions & 15 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
#![warn(missing_docs)]

//! A library for consistent and reliable error handling
//!
//! This crate defines an opinionated strategy for error handling in Rust,
Expand Down Expand Up @@ -251,13 +249,35 @@
//! [error-type]: https://github.com/DanielKeep/rust-error-type
//! [quick-error]: https://github.com/tailhook/quick-error

#![warn(missing_docs)]
#![cfg_attr(not(feature = "alloc"), no_std)]

#[cfg(feature = "backtrace")]
extern crate backtrace;

use std::error;
use std::iter::Iterator;
#[cfg(feature = "backtrace")]
use std::sync::Arc;
#[cfg(feature = "alloc")]
mod alloc {
pub use std::error;
pub use std::iter::Iterator;
#[cfg(feature = "backtrace")]
pub use std::sync::Arc;
pub use std::result::Result;
}
#[cfg(not(feature = "alloc"))]
mod alloc {
pub use core::iter::Iterator;
pub type Box<X> = ::core::marker::PhantomData<X>;
pub use core::result::Result;

pub trait Error {
fn description(&self) -> &str;

fn cause(&self) -> Option<&Error>;
}
}
// For use in the expanded macro.
#[doc(hidden)]
pub use alloc::*;

#[cfg(feature = "backtrace")]
pub use backtrace::Backtrace;
Expand All @@ -273,12 +293,12 @@ mod error_chain;
pub mod example_generated;

/// Iterator over the error chain using the `Error::cause()` method.
pub struct ErrorChainIter<'a>(pub Option<&'a error::Error>);
pub struct ErrorChainIter<'a>(pub Option<&'a Error>);

impl<'a> Iterator for ErrorChainIter<'a> {
type Item = &'a error::Error;
type Item = &'a Error;

fn next<'b>(&'b mut self) -> Option<&'a error::Error> {
fn next<'b>(&'b mut self) -> Option<&'a Error> {
match self.0.take() {
Some(e) => {
self.0 = e.cause();
Expand All @@ -303,7 +323,7 @@ pub fn make_backtrace() -> Option<Arc<Backtrace>> {

/// This trait is implemented on all the errors generated by the `error_chain`
/// macro.
pub trait ChainedError: error::Error + Send + 'static {
pub trait ChainedError: Error + Send + 'static {
/// Associated kind type.
type ErrorKind;

Expand All @@ -315,7 +335,7 @@ pub trait ChainedError: error::Error + Send + 'static {
/// of the errors from `foreign_links`.
#[cfg(feature = "backtrace")]
#[doc(hidden)]
fn extract_backtrace(e: &(error::Error + Send + 'static))
fn extract_backtrace(e: &(Error + Send + 'static))
-> Option<Option<Arc<Backtrace>>>;
}

Expand Down Expand Up @@ -345,10 +365,12 @@ impl<T, E, CE> ResultExt<T, E, CE> for Result<T, E> where CE: ChainedError, E: I
backtrace: backtrace,
})
};
#[cfg(not(feature = "backtrace"))]
#[cfg(all(not(feature = "backtrace"), feature = "alloc"))]
let error = CE::new(callback().into(), State {
next_error: Some(Box::new(e)),
});
#[cfg(not(feature = "alloc"))]
let error = CE::new(callback().into(), State {});
error
})
}
Expand All @@ -360,10 +382,11 @@ impl<T, E, CE> ResultExt<T, E, CE> for Result<T, E> where CE: ChainedError, E: I
#[doc(hidden)]
pub struct State {
/// Next error in the error chain.
pub next_error: Option<Box<error::Error + Send>>,
#[cfg(feature = "alloc")]
next_error: Option<Box<Error + Send>>,
/// Backtrace for the current error.
#[cfg(feature = "backtrace")]
pub backtrace: Option<Arc<Backtrace>>,
backtrace: Option<Arc<Backtrace>>,
}

impl Default for State {
Expand All @@ -373,10 +396,12 @@ impl Default for State {
next_error: None,
backtrace: make_backtrace(),
};
#[cfg(not(feature = "backtrace"))]
#[cfg(all(not(feature = "backtrace"), feature = "alloc"))]
let state = State {
next_error: None,
};
#[cfg(not(feature = "alloc"))]
let state = State {};
state
}
}
Expand All @@ -390,4 +415,12 @@ impl State {
let b = None;
b
}

pub fn next_error(&self) -> Option<Box<Error + Send>> {
#[cfg(feature = "alloc")]
let next = self.next_error;
#[cfg(not(feature = "alloc"))]
let next = None;
next
}
}