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

Commit fc8c53e

Browse files
committed
[WIP] Replace ChainErr with crate-level Error.
Instead of creating one trait at each macro invocation, we create it one time in this crate. Bonus point: the trait in visible in the doc of `error-chain`. TODO: - doc - Better name for ChainErr (trait and enum)
1 parent c01ab5a commit fc8c53e

File tree

2 files changed

+83
-58
lines changed

2 files changed

+83
-58
lines changed

src/lib.rs

Lines changed: 72 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,8 @@
2929
//! optional, boxed `std::error::Error + Send + 'static` object
3030
//! (which defines the `cause`, and establishes the links in the
3131
//! error chain), and a `Backtrace`.
32-
//! * The macro additionally defines a trait, by convention called
33-
//! `ChainErr`, that defines a `chain_err` method. This method
32+
//! * This crate additionally defines the trait ResultExt
33+
//! that defines a `chain_err` method. This method
3434
//! on all `std::error::Error + Send + 'static` types extends
3535
//! the error chain by boxing the current error into an opaque
3636
//! object and putting it inside a new concrete error.
@@ -42,7 +42,7 @@
4242
//! type that hides the type of the other error in the `cause` box.
4343
//! * If `RUST_BACKTRACE` is enabled, it collects a single backtrace at
4444
//! the earliest opportunity and propagates it down the stack through
45-
//! `From` and `ChainErr` conversions.
45+
//! `From` and `ResultExt` conversions.
4646
//!
4747
//! To accomplish its goals it makes some tradeoffs:
4848
//!
@@ -122,7 +122,7 @@
122122
//! // It is also possible to leave this block out entirely, or
123123
//! // leave it empty, and these names will be used automatically.
124124
//! types {
125-
//! Error, ErrorKind, ChainErr, Result;
125+
//! Error, ErrorKind, Result;
126126
//! }
127127
//!
128128
//! // Automatic conversions between this error chain and other
@@ -265,7 +265,7 @@
265265
//! To extend the error chain:
266266
//!
267267
//! ```ignore
268-
//! use errors::ChainErr;
268+
//! use error_chain::ResultExt;
269269
//! try!(do_something().chain_err(|| "something went wrong"));
270270
//! ```
271271
//!
@@ -316,6 +316,8 @@
316316
#[cfg(feature = "backtrace")]
317317
extern crate backtrace;
318318

319+
use std::error;
320+
319321
#[cfg(feature = "backtrace")]
320322
pub use backtrace::Backtrace;
321323
#[cfg(not(feature = "backtrace"))]
@@ -328,8 +330,7 @@ mod quick_error;
328330
macro_rules! error_chain {
329331
(
330332
types {
331-
$error_name:ident, $error_kind_name:ident,
332-
$chain_error_name:ident, $result_name:ident;
333+
$error_name:ident, $error_kind_name:ident, $result_name:ident;
333334
}
334335

335336
links {
@@ -495,63 +496,45 @@ macro_rules! error_chain {
495496
}
496497
}
497498

499+
impl $crate::Error for $error_name {
500+
type ErrorKind = $error_kind_name;
498501

499-
// The ChainErr trait
500-
// ------------------
501-
502-
pub trait $chain_error_name<T> {
503-
fn chain_err<F, EK>(self, callback: F) -> ::std::result::Result<T, $error_name>
504-
where F: FnOnce() -> EK,
505-
EK: Into<$error_kind_name>;
506-
}
507-
508-
impl<T, E> $chain_error_name<T> for ::std::result::Result<T, E>
509-
where E: ::std::error::Error + Send + 'static
510-
{
511-
fn chain_err<F, EK>(self, callback: F) -> ::std::result::Result<T, $error_name>
512-
where F: FnOnce() -> EK,
513-
EK: Into<$error_kind_name>
514-
{
515-
self.map_err(move |e| {
516-
let e = Box::new(e) as Box<::std::error::Error + Send + 'static>;
517-
let (e, backtrace) = backtrace_from_box(e);
518-
let backtrace = backtrace.unwrap_or_else($crate::make_backtrace);
519-
520-
$error_name(callback().into(), (Some(e), backtrace))
521-
})
502+
fn new(kind: $error_kind_name, backtrace: (Option<Box<::std::error::Error + Send + 'static>>,
503+
Option<::std::sync::Arc<$crate::Backtrace>>)) -> $error_name {
504+
$error_name(kind, backtrace)
522505
}
523-
}
524506

525-
// Use downcasts to extract the backtrace from types we know,
526-
// to avoid generating a new one. It would be better to not
527-
// define this in the macro, but types need some additional
528-
// machinery to make it work.
529-
fn backtrace_from_box(mut e: Box<::std::error::Error + Send + 'static>)
530-
-> (Box<::std::error::Error + Send + 'static>,
531-
Option<Option<::std::sync::Arc<$crate::Backtrace>>>) {
532-
let mut backtrace = None;
533-
534-
e = match e.downcast::<$error_name>() {
535-
Err(e) => e,
536-
Ok(e) => {
537-
backtrace = Some((e.1).1.clone());
538-
e as Box<::std::error::Error + Send + 'static>
539-
}
540-
};
541-
542-
$(
507+
// Use downcasts to extract the backtrace from types we know,
508+
// to avoid generating a new one. It would be better to not
509+
// define this in the macro, but types need some additional
510+
// machinery to make it work.
511+
fn backtrace_from_box(mut e: Box<::std::error::Error + Send + 'static>)
512+
-> (Box<::std::error::Error + Send + 'static>,
513+
Option<Option<::std::sync::Arc<$crate::Backtrace>>>) {
514+
let mut backtrace = None;
543515

544-
e = match e.downcast::<$link_error_path>() {
516+
e = match e.downcast::<$error_name>() {
545517
Err(e) => e,
546518
Ok(e) => {
547519
backtrace = Some((e.1).1.clone());
548520
e as Box<::std::error::Error + Send + 'static>
549521
}
550522
};
551523

552-
) *
524+
$(
525+
526+
e = match e.downcast::<$link_error_path>() {
527+
Err(e) => e,
528+
Ok(e) => {
529+
backtrace = Some((e.1).1.clone());
530+
e as Box<::std::error::Error + Send + 'static>
531+
}
532+
};
533+
534+
) *
553535

554-
(e, backtrace)
536+
(e, backtrace)
537+
}
555538
}
556539

557540
// The Result type
@@ -569,8 +552,7 @@ macro_rules! error_chain {
569552
// Case 1: types fully specified
570553
(
571554
types {
572-
$error_name:ident, $error_kind_name:ident,
573-
$chain_error_name:ident, $result_name:ident;
555+
$error_name:ident, $error_kind_name:ident, $result_name:ident;
574556
}
575557

576558
$( links {
@@ -587,7 +569,7 @@ macro_rules! error_chain {
587569
) => (
588570
error_chain! {
589571
types {
590-
$error_name, $error_kind_name, $chain_error_name, $result_name;
572+
$error_name, $error_kind_name, $result_name;
591573
}
592574

593575
links {
@@ -621,7 +603,7 @@ macro_rules! error_chain {
621603
) => (
622604
error_chain! {
623605
types {
624-
Error, ErrorKind, ChainErr, Result;
606+
Error, ErrorKind, Result;
625607
}
626608

627609
links {
@@ -705,3 +687,37 @@ pub fn make_backtrace() -> Option<Arc<Backtrace>> {
705687
pub fn make_backtrace() -> Option<Arc<Backtrace>> {
706688
None
707689
}
690+
691+
pub trait Error: error::Error + Send + 'static {
692+
type ErrorKind;
693+
fn new(kind: Self::ErrorKind, backtrace: (Option<Box<error::Error + Send + 'static>>,
694+
Option<Arc<Backtrace>>)) -> Self;
695+
fn backtrace_from_box(e: Box<error::Error + Send + 'static>)
696+
-> (Box<error::Error + Send + 'static>,
697+
Option<Option<Arc<Backtrace>>>);
698+
}
699+
700+
/// Additionnal methods for `Result`, for easy interaction with this crate.
701+
pub trait ResultExt<T, E: Error> {
702+
/// If the `Result` is an `Err` then `chain_err` evaluates the closure,
703+
/// which returns *some type that can be converted to `ErrorKind`*, boxes
704+
/// the original error to store as the cause, then returns a new error
705+
/// containing the original error.
706+
fn chain_err<F, EK>(self, callback: F) -> Result<T, E>
707+
where F: FnOnce() -> EK,
708+
EK: Into<E::ErrorKind>;
709+
}
710+
711+
impl<T, E> ResultExt<T, E> for Result<T, E> where E: Error {
712+
fn chain_err<F, EK>(self, callback: F) -> Result<T, E>
713+
where F: FnOnce() -> EK,
714+
EK: Into<E::ErrorKind> {
715+
self.map_err(move |e| {
716+
let e = Box::new(e) as Box<error::Error + Send + 'static>;
717+
let (e, backtrace) = E::backtrace_from_box(e);
718+
let backtrace = backtrace.unwrap_or_else(make_backtrace);
719+
720+
E::new(callback().into(), (Some(e), backtrace))
721+
})
722+
}
723+
}

tests/tests.rs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ extern crate error_chain;
77
fn smoke_test_1() {
88
error_chain! {
99
types {
10-
Error, ErrorKind, ChainErr, Result;
10+
Error, ErrorKind, Result;
1111
}
1212

1313
links { }
@@ -157,6 +157,15 @@ fn has_backtrace_depending_on_env() {
157157
assert!(err.backtrace().is_some());
158158
}
159159

160+
#[test]
161+
fn chain_err() {
162+
use error_chain::ResultExt;
163+
164+
error_chain! {}
165+
166+
let _: Result<()> = Err("".into()).chain_err(|| "");
167+
}
168+
160169
#[cfg(test)]
161170
mod foreign_link_test {
162171

@@ -202,7 +211,7 @@ mod foreign_link_test {
202211

203212
error_chain! {
204213
types{
205-
Error, ErrorKind, ChainErr, Result;
214+
Error, ErrorKind, Result;
206215
}
207216
links {}
208217
foreign_links {

0 commit comments

Comments
 (0)