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

[WIP] Add boxed-error feature. #69

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 .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,5 +30,6 @@ env:
global:
- secure: ncxJbvJM1vCZfcEftjsFKJMxxhKLgWKaR8Go9AMo0VB5fB2XVW/6NYO5bQEEYpOf1Nc/+2FbI2+Dkz0S/mJpUcNSfBgablCHgwU2sHse7KsoaqfHj2mf1E3exjzSHoP96hPGicC5zAjSXFjCgJPOUSGqqRaJ7z5AsJLhJT6LuK7QpvwPBZzklUN8T+n1sVmws8TNmRIbaniq/q6wYHANHcy6Dl59dx4sKwniUGiZdUhCiddVpoxbECSxc0A8mN2pk7/aW+WGxK3goBs5ZF7+JXF318F62pDcXQmR5CX6WdpenIcJ25g1Vg1WhQ4Ifpe17CN0bfxV8ShuzrQUThCDMffZCo9XySBtODdEowwK1UIpjnFLfIxjOs45Cd8o3tM2j0CfvtnjOz6BCdUU0qiwNPPNx0wFkx3ZiOfSh+FhBhvyPM12HN2tdN0esgVBItFmEci+sSIIXqjVL6DNiu5zTjbu0bs6COwlUWdmL6vmsZtq5tl7Cno9+C3szxRVAkShGydd04l9NYjqNEzTa1EPG50OsnVRKGdRiFzSxhc3BWExNKvcQ4v867t6/PpPkW6s4oXmYI3+De+8O7ExWc6a4alcrDXKlMs5fCb5Pcd4Ju9kowcjkoJo5yf2wW3Ox5R8SJpaEEpvyhx5O/qtIxjhHNzeo8Wsr/6gdNDv20r91TI=
matrix:
- FEATURES=--features=backtrace
- FEATURES=--no-default-features
- FEATURES=--no-default-features --features=boxed-error
- FEATURES=--all-features
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

- New `Variant(Error) #[attrs]` for `links` and `foreign_links`.
- Hide implementation details from the doc.
- Add `boxed-error` feature (#69).

# 0.6.1

Expand Down
5 changes: 3 additions & 2 deletions 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"]
example_generated = []
default = ["backtrace", "example-generated"]
example-generated = []
boxed-error = []

[dependencies]
backtrace = { version = "0.3", optional = true }
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,13 @@ provides a few unique features:

See the [quickstart example](examples/quickstart.rs).

## Features

- `backtrace`: generates backtraces on error creation.
- `boxed-error`: the error is boxed (see #44).
- `example-generated`: generates the example in the documentation (should be
disabled).

## License

MIT/Apache-2.0
123 changes: 90 additions & 33 deletions src/error_chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,15 +50,12 @@ macro_rules! error_chain_processed {
}

) => {
/// The Error type.
///
/// This struct is made of three things:
///
/// - an `ErrorKind` which is used to determine the type of the error.
/// - a backtrace, generated when the error is created.
/// - an error chain, used for the implementation of `Error::cause()`.
define_error!($error_name, Inner);

/// Separated for the `boxed-error` feature.
#[derive(Debug)]
pub struct $error_name {
#[doc(hidden)]
pub struct Inner {
// The members must be `pub` for `links`.
/// The kind of the error.
#[doc(hidden)]
Expand All @@ -68,16 +65,17 @@ macro_rules! error_chain_processed {
pub state: $crate::State,
}

impl Inner {
/// Used in From<ChainedError>.
pub fn into_raw(self) -> ($error_kind_name, $crate::State) {
(self.kind, self.state)
}
}

impl $crate::ChainedError for $error_name {
type ErrorKind = $error_kind_name;

fn new(kind: $error_kind_name, state: $crate::State) -> $error_name {
$error_name {
kind: kind,
state: state,
}
}

impl_chained_error_new!($error_name, $error_kind_name);
impl_extract_backtrace!($error_name
$error_kind_name
$([$link_error_path, $(#[$meta_links])*])*);
Expand All @@ -87,15 +85,13 @@ macro_rules! error_chain_processed {
impl $error_name {
/// Constructs an error from a kind, and generates a backtrace.
pub fn from_kind(kind: $error_kind_name) -> $error_name {
$error_name {
kind: kind,
state: $crate::State::default(),
}
use $crate::ChainedError;
Self::new(kind, $crate::State::default())
}

/// Returns the kind of the error.
pub fn kind(&self) -> &$error_kind_name {
&self.kind
&self.0.kind
}

/// Iterates over the error chain.
Expand All @@ -105,20 +101,20 @@ macro_rules! error_chain_processed {

/// Returns the backtrace associated with this error.
pub fn backtrace(&self) -> Option<&$crate::Backtrace> {
self.state.backtrace()
self.0.state.backtrace()
}
}

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

fn cause(&self) -> Option<&::std::error::Error> {
match self.state.next_error {
match self.0.state.next_error {
Some(ref c) => Some(&**c),
None => {
match self.kind {
match self.0.kind {
$(
$(#[$meta_foreign_links])*
$error_kind_name::$foreign_link_variant(ref foreign_err) => {
Expand All @@ -134,18 +130,17 @@ 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)
::std::fmt::Display::fmt(&self.0.kind, f)
}
}

$(
$(#[$meta_links])*
impl From<$link_error_path> for $error_name {
fn from(e: $link_error_path) -> Self {
$error_name {
kind: $error_kind_name::$link_variant(e.kind),
state: e.state,
}
use $crate::ChainedError;
let (kind, state) = e.0.into_raw();
Self::new($error_kind_name::$link_variant(kind), state)
}
}
) *
Expand Down Expand Up @@ -183,7 +178,7 @@ macro_rules! error_chain_processed {
type Target = $error_kind_name;

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

Expand Down Expand Up @@ -245,7 +240,7 @@ macro_rules! error_chain_processed {

impl From<$error_name> for $error_kind_name {
fn from(e: $error_name) -> Self {
e.kind
e.0.kind
}
}
};
Expand Down Expand Up @@ -332,13 +327,13 @@ macro_rules! impl_extract_backtrace {
fn extract_backtrace(e: &(::std::error::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());
return Some(e.0.state.backtrace.clone());
}
$(
$( #[$meta_links] )*
{
if let Some(e) = e.downcast_ref::<$link_error_path>() {
return Some(e.state.backtrace.clone());
return Some(e.0.state.backtrace.clone());
}
}
) *
Expand All @@ -360,3 +355,65 @@ macro_rules! impl_extract_backtrace {
$error_kind_name: ident
$([$link_error_path: path, $(#[$meta_links: meta])*])*) => {}
}

#[macro_export]
#[doc(hidden)]
#[cfg(feature = "boxed-error")]
macro_rules! impl_chained_error_new {
($error_name: ident, $error_kind_name: ident) => {
fn new(kind: $error_kind_name, state: $crate::State) -> $error_name {
$error_name(Box::new(Inner {
kind: kind,
state: state,
}))
}
}
}

#[macro_export]
#[doc(hidden)]
#[cfg(not(feature = "boxed-error"))]
macro_rules! impl_chained_error_new {
($error_name: ident, $error_kind_name: ident) => {
fn new(kind: $error_kind_name, state: $crate::State) -> $error_name {
$error_name(Inner {
kind: kind,
state: state,
})
}
}
}

#[macro_export]
#[doc(hidden)]
#[cfg(feature = "boxed-error")]
macro_rules! define_error {
($error_name: ident, $inner_name: ident) => {
/// The Error type.
///
/// This struct is made of three things:
///
/// - an `ErrorKind` which is used to determine the type of the error.
/// - a backtrace, generated when the error is created.
/// - an error chain, used for the implementation of `Error::cause()`.
#[derive(Debug)]
pub struct $error_name(pub Box<$inner_name>);
}
}

#[macro_export]
#[doc(hidden)]
#[cfg(not(feature = "boxed-error"))]
macro_rules! define_error {
($error_name: ident, $inner_name: ident) => {
/// The Error type.
///
/// This struct is made of three things:
///
/// - an `ErrorKind` which is used to determine the type of the error.
/// - a backtrace, generated when the error is created.
/// - an error chain, used for the implementation of `Error::cause()`.
#[derive(Debug)]
pub struct $error_name(pub $inner_name);
}
}
10 changes: 5 additions & 5 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,7 @@ pub type Backtrace = ();
mod quick_error;
#[macro_use]
mod error_chain;
#[cfg(feature = "example_generated")]
#[cfg(feature = "example-generated")]
pub mod example_generated;

/// Iterator over the error chain using the `Error::cause()` method.
Expand Down Expand Up @@ -320,18 +320,18 @@ pub trait ChainedError: error::Error + Send + 'static {
}

/// Additionnal methods for `Result`, for easy interaction with this crate.
pub trait ResultExt<T, E, CE: ChainedError> {
pub trait ResultExt<T, E> {
/// If the `Result` is an `Err` then `chain_err` evaluates the closure,
/// which returns *some type that can be converted to `ErrorKind`*, boxes
/// the original error to store as the cause, then returns a new error
/// containing the original error.
fn chain_err<F, EK>(self, callback: F) -> Result<T, CE>
fn chain_err<F, EK, CE: ChainedError>(self, callback: F) -> Result<T, CE>
where F: FnOnce() -> EK,
EK: Into<CE::ErrorKind>;
}

impl<T, E, CE> ResultExt<T, E, CE> for Result<T, E> where CE: ChainedError, E: error::Error + Send + 'static {
fn chain_err<F, EK>(self, callback: F) -> Result<T, CE>
impl<T, E> ResultExt<T, E> for Result<T, E> where E: error::Error + Send + 'static {
fn chain_err<F, EK, CE: ChainedError>(self, callback: F) -> Result<T, CE>
where F: FnOnce() -> EK,
EK: Into<CE::ErrorKind> {
self.map_err(move |e| {
Expand Down