diff options
author | Justus Winter <justus@sequoia-pgp.org> | 2018-01-22 14:59:34 +0100 |
---|---|---|
committer | Justus Winter <justus@sequoia-pgp.org> | 2018-01-23 12:15:47 +0100 |
commit | d01bb57a83b6dbef79e93639f784ee2ff6b72bf4 (patch) | |
tree | 081d6665dbff117c5b185560d8d54bf2801735a5 /core | |
parent | d7f6a55911589af3c6f0c321330c59d2a3538ae6 (diff) |
Use the failure crate to handle errors.
- The failure crate is a young error handling solution for Rust. It
may change the API, but since we pin our dependencies, this should
not be a problem for us, albeit a bit inconvenient.
- Introduction of the crate is a bit noisy, but not as bad as
anticipated, because failure magically handles all errors used in
the standard library.
- Matching on concrete error values requires downcasting before
matching, which seems a bit unidiomatic. This is the cost of
using and "chaining" arbitrary error types. This is something
that may be improved later on in the library or language.
- Having said that, using the error type in the tool was nice. I
did not have to use a downcast, so maybe my worries about
downcasts are unjustified because it is not such a common use case
after all. On the other hand, the tool is quite simple and our
only mode of failure is to print the message.
Diffstat (limited to 'core')
-rw-r--r-- | core/Cargo.toml | 1 | ||||
-rw-r--r-- | core/src/lib.rs | 83 |
2 files changed, 49 insertions, 35 deletions
diff --git a/core/Cargo.toml b/core/Cargo.toml index caafe03c..1bfb5222 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -4,4 +4,5 @@ version = "0.1.0" authors = ["Justus Winter <justus@pep-project.org>"] [dependencies] +failure = "0.1.1" tempdir = "0.3.5" diff --git a/core/src/lib.rs b/core/src/lib.rs index 72de3de3..ed2452ce 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -19,8 +19,11 @@ /// ``` extern crate tempdir; +#[macro_use] +extern crate failure; use std::env; +use std::fmt; use std::fs; use std::io; use std::path::{Path, PathBuf}; @@ -244,21 +247,18 @@ impl Config { /* Error handling. */ /// Result type for Sequoia. -pub type Result<T> = ::std::result::Result<T, Error>; +pub type Result<T> = ::std::result::Result<T, failure::Error>; +#[derive(Fail, Debug)] /// Errors for Sequoia. -#[derive(Debug)] pub enum Error { /// The network policy was violated by the given action. + #[fail(display = "Unmet network policy requirement: {}", _0)] NetworkPolicyViolation(NetworkPolicy), - /// An `io::Error` occured. - IoError(io::Error), -} - -impl From<io::Error> for Error { - fn from(error: io::Error) -> Self { - Error::IoError(error) - } + #[fail(display = "IO error: {}", error)] + IoError { error: io::Error }, + #[fail(display = "An unknown error has occurred.")] + UnknownError, } /* Network policy. */ @@ -284,10 +284,21 @@ pub enum NetworkPolicy { Insecure, } +impl fmt::Display for NetworkPolicy { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", match self { + &NetworkPolicy::Offline => "Offline", + &NetworkPolicy::Anonymized => "Anonymized", + &NetworkPolicy::Encrypted => "Encrypted", + &NetworkPolicy::Insecure => "Insecure", + }) + } +} + impl NetworkPolicy { pub fn assert(&self, action: NetworkPolicy) -> Result<()> { if action > *self { - Err(Error::NetworkPolicyViolation(action)) + Err(Error::NetworkPolicyViolation(action).into()) } else { Ok(()) } @@ -412,47 +423,49 @@ macro_rules! assert_match { mod network_policy_test { use super::{Error, NetworkPolicy}; + fn ok(policy: NetworkPolicy, required: NetworkPolicy) { + assert!(policy.assert(required).is_ok()); + } + + fn fail(policy: NetworkPolicy, required: NetworkPolicy) { + assert_match!(Error::NetworkPolicyViolation(_) + = policy.assert(required) + .err().unwrap().downcast::<Error>().unwrap()); + } + #[test] fn offline() { let p = NetworkPolicy::Offline; - assert_match!( - Err(Error::NetworkPolicyViolation(_)) = p.assert(NetworkPolicy::Anonymized)); - assert_match!( - Err(Error::NetworkPolicyViolation(_)) = p.assert(NetworkPolicy::Encrypted)); - assert_match!( - Err(Error::NetworkPolicyViolation(_)) = p.assert(NetworkPolicy::Insecure)); + ok(p, NetworkPolicy::Offline); + fail(p, NetworkPolicy::Anonymized); + fail(p, NetworkPolicy::Encrypted); + fail(p, NetworkPolicy::Insecure); } #[test] fn anonymized() { let p = NetworkPolicy::Anonymized; - assert_match!( - Ok(()) = p.assert(NetworkPolicy::Anonymized)); - assert_match!( - Err(Error::NetworkPolicyViolation(_)) = p.assert(NetworkPolicy::Encrypted)); - assert_match!( - Err(Error::NetworkPolicyViolation(_)) = p.assert(NetworkPolicy::Insecure)); + ok(p, NetworkPolicy::Offline); + ok(p, NetworkPolicy::Anonymized); + fail(p, NetworkPolicy::Encrypted); + fail(p, NetworkPolicy::Insecure); } #[test] fn encrypted() { let p = NetworkPolicy::Encrypted; - assert_match!( - Ok(()) = p.assert(NetworkPolicy::Anonymized)); - assert_match!( - Ok(()) = p.assert(NetworkPolicy::Encrypted)); - assert_match!( - Err(Error::NetworkPolicyViolation(_)) = p.assert(NetworkPolicy::Insecure)); + ok(p, NetworkPolicy::Offline); + ok(p, NetworkPolicy::Anonymized); + ok(p, NetworkPolicy::Encrypted); + fail(p, NetworkPolicy::Insecure); } #[test] fn insecure() { let p = NetworkPolicy::Insecure; - assert_match!( - Ok(()) = p.assert(NetworkPolicy::Anonymized)); - assert_match!( - Ok(()) = p.assert(NetworkPolicy::Encrypted)); - assert_match!( - Ok(()) = p.assert(NetworkPolicy::Insecure)); + ok(p, NetworkPolicy::Offline); + ok(p, NetworkPolicy::Anonymized); + ok(p, NetworkPolicy::Encrypted); + ok(p, NetworkPolicy::Insecure); } } |