From 728be3bc0aa68a1e7f8d640a719f3f172f164579 Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Sat, 27 Jan 2018 00:19:09 +0100 Subject: [PATCH] Add trait for ergonomic Options-as-Errors --- src/errors.rs | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 4 ++-- 2 files changed, 59 insertions(+), 2 deletions(-) create mode 100644 src/errors.rs diff --git a/src/errors.rs b/src/errors.rs new file mode 100644 index 0000000..4eabba1 --- /dev/null +++ b/src/errors.rs @@ -0,0 +1,57 @@ +use std::fmt::{Debug, Display}; +use std::result::Result as StdResult; +use failure::{Error, err_msg}; + +/// A handy alias for `Result` that carries a generic error type. +pub type Result = StdResult; + +/// Treat `Option::None` as Error with context +pub trait NoneErrorContext { + /// Convert Option to Result by annotating what None means + /// + /// # Examples + /// + /// ```rust + /// # extern crate quicli; + /// # use quicli::prelude::*; + /// # fn main() { assert!(run().is_err()); } + /// # fn run() -> Result<()> { + /// let xs = vec!["lorem", "ipsum"]; + /// let x = xs.get(66); // will return None + /// let result = x.none_means("index not found")?; + /// # Ok(()) } + /// ``` + fn none_means(self, explanation: E) -> Result; +} + +impl NoneErrorContext for Option { + fn none_means(self, explanation: E) -> Result { + match self { + Some(x) => Ok(x), + None => Err(err_msg(explanation)), + } + } +} + +#[cfg(test)] +mod tests { + #[test] + fn none_means_error_message() { + use prelude::*; + run().unwrap(); + + fn run() -> Result<()> { + let xs = vec!["lorem", "ipsum"]; + let x = xs.get(66); // will return None + + let result = x.none_means("index not found"); + + assert!(result.is_err()); + if let Err(error) = result { + assert_eq!(error.to_string(), "index not found".to_string()); + } + + Ok(()) + } + } +} diff --git a/src/lib.rs b/src/lib.rs index 18544c7..4d3d088 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -20,6 +20,7 @@ extern crate env_logger; pub mod fs; mod main_macro; +mod errors; mod reexports { #[doc(hidden)] pub use serde_derive::*; @@ -46,8 +47,7 @@ mod reexports { pub mod prelude { pub use reexports::*; - /// A handy alias for `Result` that carries a generic error type. - pub type Result = ::std::result::Result; + pub use errors::{Result, NoneErrorContext}; pub use fs::{read_file, write_to_file};