Skip to content

Commit 2f6eb58

Browse files
committed
Fix --help and modernize
We rip out `error-chain`, add a custom parser for options that specify a character and, and generally clean things up a bit. We also fix some missing `--help` documentation.
1 parent 768b064 commit 2f6eb58

File tree

6 files changed

+176
-137
lines changed

6 files changed

+176
-137
lines changed

scrubcsv/.vscode/settings.json

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"editor.formatOnSave": true,
3+
"editor.formatOnPaste": true
4+
}

scrubcsv/Cargo.lock

-51
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

scrubcsv/Cargo.toml

-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ opt-level = 3
1919
clap = "2.33.0"
2020
csv = "1"
2121
env_logger = "0.7"
22-
error-chain = "0.12"
2322
humansize = "1.0.1"
2423
lazy_static = "1.2.0"
2524
libc = "0.2.18"

scrubcsv/src/errors.rs

+76-19
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,81 @@
1-
//! Error-handling support implemented using the `[error-chain][]` crate.
1+
//! Error-handling support. This emulates libraries like `error-chain` (very
2+
//! deprecated), `failure` (somewhat deprecated) and `snafu` (currently
3+
//! recommended, but I'm starting to see a pattern here).
24
//!
3-
//! [error-chain]: https://docs.rs/error-chain
4-
5-
use csv;
6-
use std::io;
7-
8-
// Declare nicer `Error` and `Result` types. This is a macro that
9-
// generates a lot of boilerplate code for us.
10-
error_chain! {
11-
// Error types from other libraries that we want to just wrap
12-
// automatically.
13-
foreign_links {
14-
Csv(csv::Error);
15-
Io(io::Error);
5+
//! I just wanted to see how hard it was to roll an nice error API from scratch
6+
//! instead of depending on an unstable third-party library.
7+
8+
use std::{error, fmt, result};
9+
10+
/// Our error type. We used a boxed dynamic error because we don't care much
11+
/// about the details and we're only going to print it for the user anyways.
12+
pub type Error = Box<dyn error::Error + 'static>;
13+
14+
/// Our custom `Result` type. Defaults the `E` parameter to our error type.
15+
pub type Result<T, E = Error> = result::Result<T, E>;
16+
17+
/// Human-readable context for another error.
18+
#[derive(Debug)]
19+
pub struct Context {
20+
context: String,
21+
source: Error,
22+
}
23+
24+
impl fmt::Display for Context {
25+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
26+
self.context.fmt(f)
27+
}
28+
}
29+
30+
impl error::Error for Context {
31+
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
32+
Some(self.source.as_ref())
33+
}
34+
}
35+
36+
/// Extend `Result` with methods that add context to errors.
37+
pub trait ResultExt<T, E>: Sized {
38+
/// If this result is an error, wrap that error with `context`.
39+
fn context<C>(self, context: C) -> Result<T>
40+
where
41+
C: Into<String>,
42+
{
43+
self.with_context(|_| context.into())
1644
}
1745

18-
errors {
19-
CannotParseCharacter(specifier: String) {
20-
description("cannot parse character specifier")
21-
display("cannot parse character specifier: '{}'", specifier)
22-
}
46+
/// If this result is an error, call `build_context` and wrap the error in
47+
/// that context.
48+
fn with_context<C, F>(self, build_context: F) -> Result<T>
49+
where
50+
C: Into<String>,
51+
F: FnOnce(&E) -> C;
52+
}
53+
54+
impl<T, E: error::Error + 'static> ResultExt<T, E> for Result<T, E> {
55+
fn with_context<C, F>(self, build_context: F) -> Result<T>
56+
where
57+
C: Into<String>,
58+
F: FnOnce(&E) -> C,
59+
{
60+
self.map_err(|err| {
61+
Box::new(Context {
62+
context: build_context(&err).into(),
63+
source: Box::new(err),
64+
}) as Error
65+
})
2366
}
2467
}
68+
69+
/// Format a string and return it as an `Error`. We use a macro to do this,
70+
/// because that's the only way to declare `format!`-like syntax in Rust.
71+
#[macro_export]
72+
macro_rules! format_err {
73+
($format_str:literal) => ({
74+
let err: $crate::errors::Error = format!($format_str).into();
75+
err
76+
});
77+
($format_str:literal, $($arg:expr),*) => ({
78+
let err: $crate::errors::Error = format!($format_str, $($arg),*).into();
79+
err
80+
});
81+
}

0 commit comments

Comments
 (0)