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

Commit e781ed5

Browse files
TedDriggsYamakaky
authored andcommitted
Added chain_err method to Error implementations (#141)
* Added `caused` method to Error implementations * Removed use of experimental ".." * Added method to ChainedErr trait * Restore accidentally-removed indentation * Actually fixed all the whitespace * Renamed "caused" to "chain_err" for consistency; added docs * Fix broken test * Added `caused` method to Error implementations * Removed use of experimental ".." * Added method to ChainedErr trait * Restore accidentally-removed indentation * Actually fixed all the whitespace * Renamed "caused" to "chain_err" for consistency; added docs * Fix broken test * Renamed a test to match new method name * Fixed changelog
1 parent b8f4e06 commit e781ed5

File tree

5 files changed

+114
-1
lines changed

5 files changed

+114
-1
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
# Unreleased
22

3+
- [Add a new method for `Error`: `chain_err`.](https://github.com/brson/error-chain/pull/141)
4+
35
# 0.10.0
46

57
- [Add a new constructor for `Error`: `with_chain`.](https://github.com/brson/error-chain/pull/126)

examples/chain_err.rs

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
//! Demonstrates usage of `Error::caused` method. This method enables chaining errors
2+
//! like `ResultExt::chain_err` but doesn't require the presence of a `Result` wrapper.
3+
4+
#[macro_use]
5+
extern crate error_chain;
6+
7+
use std::fs::File;
8+
9+
mod errors {
10+
use std::io;
11+
use super::LaunchStage;
12+
13+
error_chain! {
14+
foreign_links {
15+
Io(io::Error) #[doc = "Error during IO"];
16+
}
17+
18+
errors {
19+
Launch(phase: LaunchStage) {
20+
description("An error occurred during startup")
21+
display("Startup aborted: {:?} did not complete successfully", phase)
22+
}
23+
24+
ConfigLoad(path: String) {
25+
description("Config file not found")
26+
display("Unable to read file `{}`", path)
27+
}
28+
}
29+
}
30+
31+
impl From<LaunchStage> for ErrorKind {
32+
fn from(v: LaunchStage) -> Self {
33+
ErrorKind::Launch(v)
34+
}
35+
}
36+
}
37+
38+
pub use errors::*;
39+
40+
#[derive(Debug, Clone, PartialEq, Eq)]
41+
pub enum LaunchStage {
42+
ConfigLoad,
43+
ConfigParse,
44+
ConfigResolve,
45+
}
46+
47+
/// Read the service config from the file specified.
48+
fn load_config(rel_path: &str) -> Result<()> {
49+
File::open(rel_path)
50+
.map(|_| ())
51+
.chain_err(|| ErrorKind::ConfigLoad(rel_path.to_string()))
52+
}
53+
54+
/// Launch the service.
55+
fn launch(rel_path: &str) -> Result<()> {
56+
load_config(rel_path).map_err(|e| match e {
57+
e @ Error(ErrorKind::ConfigLoad(_), _) => e.chain_err(|| LaunchStage::ConfigLoad),
58+
e => e.chain_err(|| "Unknown failure")
59+
})
60+
}
61+
62+
fn main() {
63+
let chain = launch("does_not_exist.json").unwrap_err();
64+
for err in chain.iter() {
65+
println!("{}", err);
66+
}
67+
}

src/error_chain.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,12 @@ macro_rules! error_chain_processed {
100100
$crate::ErrorChainIter(Some(self))
101101
}
102102

103+
fn chain_err<F, EK>(self, error: F) -> Self
104+
where F: FnOnce() -> EK,
105+
EK: Into<$error_kind_name> {
106+
self.chain_err(error)
107+
}
108+
103109
fn backtrace(&self) -> Option<&$crate::Backtrace> {
104110
self.backtrace()
105111
}
@@ -145,6 +151,12 @@ macro_rules! error_chain_processed {
145151
pub fn backtrace(&self) -> Option<&$crate::Backtrace> {
146152
self.1.backtrace()
147153
}
154+
155+
/// Extends the error chain with a new entry.
156+
pub fn chain_err<F, EK>(self, error: F) -> $error_name
157+
where F: FnOnce() -> EK, EK: Into<$error_kind_name> {
158+
$error_name::with_chain(self, Self::from_kind(error().into()))
159+
}
148160
}
149161

150162
impl ::std::error::Error for $error_name {

src/lib.rs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,9 @@
257257
//! ```
258258
//!
259259
//! ## Chaining errors
260-
//!
260+
//! error-chain supports extending an error chain by appending new errors.
261+
//! This can be done on a Result or on an existing Error.
262+
//!
261263
//! To extend the error chain:
262264
//!
263265
//! ```
@@ -279,6 +281,11 @@
279281
//! boxes the original error to store as the cause, then returns a new
280282
//! error containing the original error.
281283
//!
284+
//! Calling `chain_err` on an existing `Error` instance has the same
285+
//! signature and produces the same outcome as being called on a `Result`
286+
//! matching the properties described above. This is most useful when
287+
//! partially handling errors using the `map_err` function.
288+
//!
282289
//! To chain an error directly, use `with_chain`:
283290
//!
284291
//! ```
@@ -499,6 +506,11 @@ pub trait ChainedError: error::Error + Send + 'static {
499506
Display(self)
500507
}
501508

509+
/// Extends the error chain with a new entry.
510+
fn chain_err<F, EK>(self, error: F) -> Self
511+
where F: FnOnce() -> EK,
512+
EK: Into<Self::ErrorKind>;
513+
502514
/// Creates an error from its parts.
503515
#[doc(hidden)]
504516
fn new(kind: Self::ErrorKind, state: State) -> Self where Self: Sized;

tests/tests.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,26 @@ fn chain_err() {
251251
let _: Result<()> = Err(Error::from_kind(ErrorKind::Test)).chain_err(|| "");
252252
}
253253

254+
/// Verify that an error chain is extended one by `Error::chain_err`, with
255+
/// the new error added to the end.
256+
#[test]
257+
fn error_chain_err() {
258+
error_chain! {
259+
errors {
260+
Test
261+
}
262+
}
263+
264+
let base = Error::from(ErrorKind::Test);
265+
let ext = base.chain_err(|| "Test passes");
266+
267+
if let Error(ErrorKind::Msg(_), _) = ext {
268+
// pass
269+
} else {
270+
panic!("The error should be wrapped. {:?}", ext);
271+
}
272+
}
273+
254274
#[test]
255275
fn links() {
256276
mod test {

0 commit comments

Comments
 (0)