1
+ #![ warn( missing_docs) ]
2
+
1
3
//! A library for consistent and reliable error handling
2
4
//!
3
5
//! This crate defines an opinionated strategy for error handling in Rust,
29
31
//! optional, boxed `std::error::Error + Send + 'static` object
30
32
//! (which defines the `cause`, and establishes the links in the
31
33
//! 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
34
+ //! * This crate additionally defines the trait ResultExt
35
+ //! that defines a `chain_err` method. This method
34
36
//! on all `std::error::Error + Send + 'static` types extends
35
37
//! the error chain by boxing the current error into an opaque
36
38
//! object and putting it inside a new concrete error.
42
44
//! type that hides the type of the other error in the `cause` box.
43
45
//! * If `RUST_BACKTRACE` is enabled, it collects a single backtrace at
44
46
//! the earliest opportunity and propagates it down the stack through
45
- //! `From` and `ChainErr ` conversions.
47
+ //! `From` and `ResultExt ` conversions.
46
48
//!
47
49
//! To accomplish its goals it makes some tradeoffs:
48
50
//!
122
124
//! // It is also possible to leave this block out entirely, or
123
125
//! // leave it empty, and these names will be used automatically.
124
126
//! types {
125
- //! Error, ErrorKind, ChainErr, Result;
127
+ //! Error, ErrorKind, Result;
126
128
//! }
127
129
//!
128
130
//! // Automatic conversions between this error chain and other
135
137
//! //
136
138
//! // This section can be empty.
137
139
//! links {
138
- //! ::rustup_dist::Error, rustup_dist::ErrorKind, Dist;
139
- //! ::rustup_utils::Error, rustup_utils::ErrorKind, Utils, #[cfg(unix)];
140
+ //! ::rustup_dist::Error, Dist;
141
+ //! ::rustup_utils::Error, Utils, #[cfg(unix)];
140
142
//! }
141
143
//!
142
144
//! // Automatic conversions between this error chain and other
265
267
//! To extend the error chain:
266
268
//!
267
269
//! ```ignore
268
- //! use errors::ChainErr ;
270
+ //! use error_chain::ResultExt ;
269
271
//! try!(do_something().chain_err(|| "something went wrong"));
270
272
//! ```
271
273
//!
316
318
#[ cfg( feature = "backtrace" ) ]
317
319
extern crate backtrace;
318
320
321
+ use std:: error;
322
+ use std:: iter:: Iterator ;
323
+ use std:: sync:: Arc ;
324
+
319
325
#[ cfg( feature = "backtrace" ) ]
320
326
pub use backtrace:: Backtrace ;
321
327
#[ cfg( not( feature = "backtrace" ) ) ]
@@ -328,12 +334,11 @@ mod quick_error;
328
334
macro_rules! error_chain {
329
335
(
330
336
types {
331
- $error_name: ident, $error_kind_name: ident,
332
- $chain_error_name: ident, $result_name: ident;
337
+ $error_name: ident, $error_kind_name: ident, $result_name: ident;
333
338
}
334
339
335
340
links {
336
- $( $link_error_path: path, $link_kind_path : path , $ link_variant: ident $( , #[ $meta_links: meta] ) * ; ) *
341
+ $( $link_error_path: path, $link_variant: ident $( , #[ $meta_links: meta] ) * ; ) *
337
342
}
338
343
339
344
foreign_links {
@@ -347,27 +352,28 @@ macro_rules! error_chain {
347
352
) => {
348
353
349
354
350
- // The Error type
351
- // --------------
352
-
353
- // This has a simple structure to support pattern matching
354
- // during error handling. The second field is internal state
355
- // that is mostly irrelevant for error handling purposes.
355
+ /// The Error type
356
+ ///
357
+ /// This has a simple structure to support pattern matching
358
+ /// during error handling. The second field is internal state
359
+ /// that is mostly irrelevant for error handling purposes.
356
360
#[ derive( Debug ) ]
357
361
pub struct $error_name( pub $error_kind_name,
358
362
pub ( Option <Box <:: std:: error:: Error + Send >>,
359
363
Option <:: std:: sync:: Arc <$crate:: Backtrace >>) ) ;
360
364
361
- #[ allow( unused) ]
362
365
impl $error_name {
366
+ /// Returns the kind of the error.
363
367
pub fn kind( & self ) -> & $error_kind_name {
364
368
& self . 0
365
369
}
366
370
371
+ /// Iterates over the error chain.
367
372
pub fn iter( & self ) -> $crate:: ErrorChainIter {
368
373
$crate:: ErrorChainIter ( Some ( self ) )
369
374
}
370
375
376
+ /// Returns the backtrace associated with this error.
371
377
pub fn backtrace( & self ) -> Option <& $crate:: Backtrace > {
372
378
( self . 1 ) . 1 . as_ref( ) . map( |v| & * * v)
373
379
}
@@ -446,6 +452,7 @@ macro_rules! error_chain {
446
452
// --------------
447
453
448
454
quick_error! {
455
+ /// The kind of an error
449
456
#[ derive( Debug ) ]
450
457
pub enum $error_kind_name {
451
458
@@ -456,7 +463,7 @@ macro_rules! error_chain {
456
463
457
464
$(
458
465
$( #[ $meta_links] ) *
459
- $link_variant( e: $link_kind_path ) {
466
+ $link_variant( e: <$link_error_path as $crate :: ChainedError > :: ErrorKind ) {
460
467
description( e. description( ) )
461
468
display( "{}" , e)
462
469
}
@@ -476,8 +483,8 @@ macro_rules! error_chain {
476
483
477
484
$(
478
485
$( #[ $meta_links] ) *
479
- impl From <$link_kind_path > for $error_kind_name {
480
- fn from( e: $link_kind_path ) -> Self {
486
+ impl From <<$link_error_path as $crate :: ChainedError > :: ErrorKind > for $error_kind_name {
487
+ fn from( e: <$link_error_path as $crate :: ChainedError > :: ErrorKind ) -> Self {
481
488
$error_kind_name:: $link_variant( e)
482
489
}
483
490
}
@@ -495,68 +502,34 @@ macro_rules! error_chain {
495
502
}
496
503
}
497
504
505
+ impl $crate:: ChainedError for $error_name {
506
+ type ErrorKind = $error_kind_name;
498
507
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
- } )
508
+ fn new( kind: $error_kind_name, backtrace: ( Option <Box <:: std:: error:: Error + Send + ' static >>,
509
+ Option <:: std:: sync:: Arc <$crate:: Backtrace >>) ) -> $error_name {
510
+ $error_name( kind, backtrace)
522
511
}
523
- }
524
512
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 >
513
+ fn extract_backtrace( e: & ( :: std:: error:: Error + Send + ' static ) )
514
+ -> Option <Option <:: std:: sync:: Arc <$crate:: Backtrace >>> {
515
+ if let Some ( e) = e. downcast_ref:: <$error_name>( ) {
516
+ Some ( ( e. 1 ) . 1 . clone( ) )
539
517
}
540
- } ;
541
-
542
- $(
543
-
544
- e = match e. downcast:: <$link_error_path>( ) {
545
- Err ( e) => e,
546
- Ok ( e) => {
547
- backtrace = Some ( ( e. 1 ) . 1 . clone( ) ) ;
548
- e as Box <:: std:: error:: Error + Send + ' static >
518
+ $(
519
+ else if let Some ( e) = e. downcast_ref:: <$link_error_path>( ) {
520
+ Some ( ( e. 1 ) . 1 . clone( ) )
549
521
}
550
- } ;
551
-
552
- ) *
553
-
554
- ( e , backtrace )
522
+ ) *
523
+ else {
524
+ None
525
+ }
526
+ }
555
527
}
556
528
557
529
// The Result type
558
530
// ---------------
559
531
532
+ /// Convenient wrapper around std::Result.
560
533
pub type $result_name<T > = :: std:: result:: Result <T , $error_name>;
561
534
} ;
562
535
@@ -569,8 +542,7 @@ macro_rules! error_chain {
569
542
// Case 1: types fully specified
570
543
(
571
544
types {
572
- $error_name: ident, $error_kind_name: ident,
573
- $chain_error_name: ident, $result_name: ident;
545
+ $error_name: ident, $error_kind_name: ident, $result_name: ident;
574
546
}
575
547
576
548
$( links {
@@ -587,7 +559,7 @@ macro_rules! error_chain {
587
559
) => (
588
560
error_chain! {
589
561
types {
590
- $error_name, $error_kind_name, $chain_error_name , $ result_name;
562
+ $error_name, $error_kind_name, $result_name;
591
563
}
592
564
593
565
links {
@@ -621,7 +593,7 @@ macro_rules! error_chain {
621
593
) => (
622
594
error_chain! {
623
595
types {
624
- Error , ErrorKind , ChainErr , Result ;
596
+ Error , ErrorKind , Result ;
625
597
}
626
598
627
599
links {
@@ -669,17 +641,13 @@ macro_rules! error_chain {
669
641
) ;
670
642
}
671
643
672
-
673
- use std:: error:: Error as StdError ;
674
- use std:: iter:: Iterator ;
675
- use std:: sync:: Arc ;
676
-
677
- pub struct ErrorChainIter < ' a > ( pub Option < & ' a StdError > ) ;
644
+ /// Iterator over the error chain.
645
+ pub struct ErrorChainIter < ' a > ( pub Option < & ' a error:: Error > ) ;
678
646
679
647
impl < ' a > Iterator for ErrorChainIter < ' a > {
680
- type Item = & ' a StdError ;
648
+ type Item = & ' a error :: Error ;
681
649
682
- fn next < ' b > ( & ' b mut self ) -> Option < & ' a StdError > {
650
+ fn next < ' b > ( & ' b mut self ) -> Option < & ' a error :: Error > {
683
651
match self . 0 . take ( ) {
684
652
Some ( e) => {
685
653
self . 0 = e. cause ( ) ;
@@ -694,6 +662,7 @@ impl<'a> Iterator for ErrorChainIter<'a> {
694
662
/// is set to anything but ``0``, and `None` otherwise. This is used
695
663
/// in the generated error implementations.
696
664
#[ cfg( feature = "backtrace" ) ]
665
+ #[ doc( hidden) ]
697
666
pub fn make_backtrace ( ) -> Option < Arc < Backtrace > > {
698
667
match std:: env:: var_os ( "RUST_BACKTRACE" ) {
699
668
Some ( ref val) if val != "0" => Some ( Arc :: new ( Backtrace :: new ( ) ) ) ,
@@ -702,6 +671,48 @@ pub fn make_backtrace() -> Option<Arc<Backtrace>> {
702
671
}
703
672
704
673
#[ cfg( not( feature = "backtrace" ) ) ]
674
+ #[ doc( hidden) ]
705
675
pub fn make_backtrace ( ) -> Option < Arc < Backtrace > > {
706
676
None
707
677
}
678
+
679
+ /// This trait is an implementation detail which must be implemented on each
680
+ /// ErrorKind. We can't do it globally since each ErrorKind is different.
681
+ pub trait ChainedError : error:: Error + Send + ' static {
682
+ /// Associated kind type.
683
+ type ErrorKind ;
684
+ /// Creates an error from it's parts.
685
+ fn new ( kind : Self :: ErrorKind ,
686
+ state : ( Option < Box < error:: Error + Send + ' static > > ,
687
+ Option < Arc < Backtrace > > ) ) -> Self ;
688
+ /// Use downcasts to extract the backtrace from types we know,
689
+ /// to avoid generating a new one. It would be better to not
690
+ /// define this in the macro, but types need some additional
691
+ /// machinery to make it work.
692
+ fn extract_backtrace ( e : & ( error:: Error + Send + ' static ) )
693
+ -> Option < Option < Arc < Backtrace > > > ;
694
+ }
695
+
696
+ /// Additionnal methods for `Result`, for easy interaction with this crate.
697
+ pub trait ResultExt < T , E : ChainedError > {
698
+ /// If the `Result` is an `Err` then `chain_err` evaluates the closure,
699
+ /// which returns *some type that can be converted to `ErrorKind`*, boxes
700
+ /// the original error to store as the cause, then returns a new error
701
+ /// containing the original error.
702
+ fn chain_err < F , EK > ( self , callback : F ) -> Result < T , E >
703
+ where F : FnOnce ( ) -> EK ,
704
+ EK : Into < E :: ErrorKind > ;
705
+ }
706
+
707
+ impl < T , E > ResultExt < T , E > for Result < T , E > where E : ChainedError {
708
+ fn chain_err < F , EK > ( self , callback : F ) -> Result < T , E >
709
+ where F : FnOnce ( ) -> EK ,
710
+ EK : Into < E :: ErrorKind > {
711
+ self . map_err ( move |e| {
712
+ let backtrace =
713
+ E :: extract_backtrace ( & e) . unwrap_or_else ( make_backtrace) ;
714
+
715
+ E :: new ( callback ( ) . into ( ) , ( Some ( Box :: new ( e) ) , backtrace) )
716
+ } )
717
+ }
718
+ }
0 commit comments