summaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
authorJustus Winter <justus@sequoia-pgp.org>2018-01-22 14:59:34 +0100
committerJustus Winter <justus@sequoia-pgp.org>2018-01-23 12:15:47 +0100
commitd01bb57a83b6dbef79e93639f784ee2ff6b72bf4 (patch)
tree081d6665dbff117c5b185560d8d54bf2801735a5 /core
parentd7f6a55911589af3c6f0c321330c59d2a3538ae6 (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.toml1
-rw-r--r--core/src/lib.rs83
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);
}
}