29
29
//! optional, boxed `std::error::Error + Send + 'static` object
30
30
//! (which defines the `cause`, and establishes the links in the
31
31
//! 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
34
34
//! on all `std::error::Error + Send + 'static` types extends
35
35
//! the error chain by boxing the current error into an opaque
36
36
//! object and putting it inside a new concrete error.
42
42
//! type that hides the type of the other error in the `cause` box.
43
43
//! * If `RUST_BACKTRACE` is enabled, it collects a single backtrace at
44
44
//! the earliest opportunity and propagates it down the stack through
45
- //! `From` and `ChainErr ` conversions.
45
+ //! `From` and `ResultExt ` conversions.
46
46
//!
47
47
//! To accomplish its goals it makes some tradeoffs:
48
48
//!
122
122
//! // It is also possible to leave this block out entirely, or
123
123
//! // leave it empty, and these names will be used automatically.
124
124
//! types {
125
- //! Error, ErrorKind, ChainErr, Result;
125
+ //! Error, ErrorKind, Result;
126
126
//! }
127
127
//!
128
128
//! // Automatic conversions between this error chain and other
265
265
//! To extend the error chain:
266
266
//!
267
267
//! ```ignore
268
- //! use errors::ChainErr ;
268
+ //! use error_chain::ResultExt ;
269
269
//! try!(do_something().chain_err(|| "something went wrong"));
270
270
//! ```
271
271
//!
316
316
#[ cfg( feature = "backtrace" ) ]
317
317
extern crate backtrace;
318
318
319
+ use std:: error;
320
+
319
321
#[ cfg( feature = "backtrace" ) ]
320
322
pub use backtrace:: Backtrace ;
321
323
#[ cfg( not( feature = "backtrace" ) ) ]
@@ -328,8 +330,7 @@ mod quick_error;
328
330
macro_rules! error_chain {
329
331
(
330
332
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;
333
334
}
334
335
335
336
links {
@@ -495,63 +496,45 @@ macro_rules! error_chain {
495
496
}
496
497
}
497
498
499
+ impl $crate:: Error for $error_name {
500
+ type ErrorKind = $error_kind_name;
498
501
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)
522
505
}
523
- }
524
506
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 ;
543
515
544
- e = match e. downcast:: <$link_error_path >( ) {
516
+ e = match e. downcast:: <$error_name >( ) {
545
517
Err ( e) => e,
546
518
Ok ( e) => {
547
519
backtrace = Some ( ( e. 1 ) . 1 . clone( ) ) ;
548
520
e as Box <:: std:: error:: Error + Send + ' static >
549
521
}
550
522
} ;
551
523
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
+ ) *
553
535
554
- ( e, backtrace)
536
+ ( e, backtrace)
537
+ }
555
538
}
556
539
557
540
// The Result type
@@ -569,8 +552,7 @@ macro_rules! error_chain {
569
552
// Case 1: types fully specified
570
553
(
571
554
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;
574
556
}
575
557
576
558
$( links {
@@ -587,7 +569,7 @@ macro_rules! error_chain {
587
569
) => (
588
570
error_chain! {
589
571
types {
590
- $error_name, $error_kind_name, $chain_error_name , $ result_name;
572
+ $error_name, $error_kind_name, $result_name;
591
573
}
592
574
593
575
links {
@@ -621,7 +603,7 @@ macro_rules! error_chain {
621
603
) => (
622
604
error_chain! {
623
605
types {
624
- Error , ErrorKind , ChainErr , Result ;
606
+ Error , ErrorKind , Result ;
625
607
}
626
608
627
609
links {
@@ -705,3 +687,37 @@ pub fn make_backtrace() -> Option<Arc<Backtrace>> {
705
687
pub fn make_backtrace ( ) -> Option < Arc < Backtrace > > {
706
688
None
707
689
}
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
+ }
0 commit comments