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

Commit 519a2c2

Browse files
committed
Merge branch 'chainerr'
2 parents c01ab5a + 0657638 commit 519a2c2

File tree

4 files changed

+125
-88
lines changed

4 files changed

+125
-88
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
- Conditional compilation for error variants.
44
- Backtrace generation is now a feature.
55
- More standard trait implementations for extra convenience.
6+
- Remove ChainErr.
7+
- Remove need to specify `ErrorKind` in `links {}`.
8+
- Add ResultExt trait.
69

710
# 0.5.0
811

src/lib.rs

Lines changed: 95 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
#![warn(missing_docs)]
2+
13
//! A library for consistent and reliable error handling
24
//!
35
//! This crate defines an opinionated strategy for error handling in Rust,
@@ -29,8 +31,8 @@
2931
//! optional, boxed `std::error::Error + Send + 'static` object
3032
//! (which defines the `cause`, and establishes the links in the
3133
//! 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
3436
//! on all `std::error::Error + Send + 'static` types extends
3537
//! the error chain by boxing the current error into an opaque
3638
//! object and putting it inside a new concrete error.
@@ -42,7 +44,7 @@
4244
//! type that hides the type of the other error in the `cause` box.
4345
//! * If `RUST_BACKTRACE` is enabled, it collects a single backtrace at
4446
//! the earliest opportunity and propagates it down the stack through
45-
//! `From` and `ChainErr` conversions.
47+
//! `From` and `ResultExt` conversions.
4648
//!
4749
//! To accomplish its goals it makes some tradeoffs:
4850
//!
@@ -122,7 +124,7 @@
122124
//! // It is also possible to leave this block out entirely, or
123125
//! // leave it empty, and these names will be used automatically.
124126
//! types {
125-
//! Error, ErrorKind, ChainErr, Result;
127+
//! Error, ErrorKind, Result;
126128
//! }
127129
//!
128130
//! // Automatic conversions between this error chain and other
@@ -135,8 +137,8 @@
135137
//! //
136138
//! // This section can be empty.
137139
//! 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)];
140142
//! }
141143
//!
142144
//! // Automatic conversions between this error chain and other
@@ -265,7 +267,7 @@
265267
//! To extend the error chain:
266268
//!
267269
//! ```ignore
268-
//! use errors::ChainErr;
270+
//! use error_chain::ResultExt;
269271
//! try!(do_something().chain_err(|| "something went wrong"));
270272
//! ```
271273
//!
@@ -316,6 +318,10 @@
316318
#[cfg(feature = "backtrace")]
317319
extern crate backtrace;
318320

321+
use std::error;
322+
use std::iter::Iterator;
323+
use std::sync::Arc;
324+
319325
#[cfg(feature = "backtrace")]
320326
pub use backtrace::Backtrace;
321327
#[cfg(not(feature = "backtrace"))]
@@ -328,12 +334,11 @@ mod quick_error;
328334
macro_rules! error_chain {
329335
(
330336
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;
333338
}
334339

335340
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])*; ) *
337342
}
338343

339344
foreign_links {
@@ -347,27 +352,28 @@ macro_rules! error_chain {
347352
) => {
348353

349354

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.
356360
#[derive(Debug)]
357361
pub struct $error_name(pub $error_kind_name,
358362
pub (Option<Box<::std::error::Error + Send>>,
359363
Option<::std::sync::Arc<$crate::Backtrace>>));
360364

361-
#[allow(unused)]
362365
impl $error_name {
366+
/// Returns the kind of the error.
363367
pub fn kind(&self) -> &$error_kind_name {
364368
&self.0
365369
}
366370

371+
/// Iterates over the error chain.
367372
pub fn iter(&self) -> $crate::ErrorChainIter {
368373
$crate::ErrorChainIter(Some(self))
369374
}
370375

376+
/// Returns the backtrace associated with this error.
371377
pub fn backtrace(&self) -> Option<&$crate::Backtrace> {
372378
(self.1).1.as_ref().map(|v| &**v)
373379
}
@@ -446,6 +452,7 @@ macro_rules! error_chain {
446452
// --------------
447453

448454
quick_error! {
455+
/// The kind of an error
449456
#[derive(Debug)]
450457
pub enum $error_kind_name {
451458

@@ -456,7 +463,7 @@ macro_rules! error_chain {
456463

457464
$(
458465
$(#[$meta_links])*
459-
$link_variant(e: $link_kind_path) {
466+
$link_variant(e: <$link_error_path as $crate::ChainedError>::ErrorKind) {
460467
description(e.description())
461468
display("{}", e)
462469
}
@@ -476,8 +483,8 @@ macro_rules! error_chain {
476483

477484
$(
478485
$(#[$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 {
481488
$error_kind_name::$link_variant(e)
482489
}
483490
}
@@ -495,68 +502,34 @@ macro_rules! error_chain {
495502
}
496503
}
497504

505+
impl $crate::ChainedError for $error_name {
506+
type ErrorKind = $error_kind_name;
498507

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)
522511
}
523-
}
524512

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())
539517
}
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())
549521
}
550-
};
551-
552-
) *
553-
554-
(e, backtrace)
522+
) *
523+
else {
524+
None
525+
}
526+
}
555527
}
556528

557529
// The Result type
558530
// ---------------
559531

532+
/// Convenient wrapper around std::Result.
560533
pub type $result_name<T> = ::std::result::Result<T, $error_name>;
561534
};
562535

@@ -569,8 +542,7 @@ macro_rules! error_chain {
569542
// Case 1: types fully specified
570543
(
571544
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;
574546
}
575547

576548
$( links {
@@ -587,7 +559,7 @@ macro_rules! error_chain {
587559
) => (
588560
error_chain! {
589561
types {
590-
$error_name, $error_kind_name, $chain_error_name, $result_name;
562+
$error_name, $error_kind_name, $result_name;
591563
}
592564

593565
links {
@@ -621,7 +593,7 @@ macro_rules! error_chain {
621593
) => (
622594
error_chain! {
623595
types {
624-
Error, ErrorKind, ChainErr, Result;
596+
Error, ErrorKind, Result;
625597
}
626598

627599
links {
@@ -669,17 +641,13 @@ macro_rules! error_chain {
669641
);
670642
}
671643

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>);
678646

679647
impl<'a> Iterator for ErrorChainIter<'a> {
680-
type Item = &'a StdError;
648+
type Item = &'a error::Error;
681649

682-
fn next<'b>(&'b mut self) -> Option<&'a StdError> {
650+
fn next<'b>(&'b mut self) -> Option<&'a error::Error> {
683651
match self.0.take() {
684652
Some(e) => {
685653
self.0 = e.cause();
@@ -694,6 +662,7 @@ impl<'a> Iterator for ErrorChainIter<'a> {
694662
/// is set to anything but ``0``, and `None` otherwise. This is used
695663
/// in the generated error implementations.
696664
#[cfg(feature = "backtrace")]
665+
#[doc(hidden)]
697666
pub fn make_backtrace() -> Option<Arc<Backtrace>> {
698667
match std::env::var_os("RUST_BACKTRACE") {
699668
Some(ref val) if val != "0" => Some(Arc::new(Backtrace::new())),
@@ -702,6 +671,48 @@ pub fn make_backtrace() -> Option<Arc<Backtrace>> {
702671
}
703672

704673
#[cfg(not(feature = "backtrace"))]
674+
#[doc(hidden)]
705675
pub fn make_backtrace() -> Option<Arc<Backtrace>> {
706676
None
707677
}
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+
}

src/quick_error.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -309,6 +309,7 @@ macro_rules! quick_error {
309309
}*/
310310
#[allow(unused)]
311311
impl $name {
312+
/// A string describing the error kind.
312313
pub fn description(&self) -> &str {
313314
match *self {
314315
$(

0 commit comments

Comments
 (0)