|
| 1 | +use std::fmt::{Debug, Display}; |
| 2 | +use std::result::Result as StdResult; |
| 3 | +use failure::{Error, err_msg}; |
| 4 | + |
| 5 | +/// A handy alias for `Result` that carries a generic error type. |
| 6 | +pub type Result<T> = StdResult<T, Error>; |
| 7 | + |
| 8 | +/// Treat `Option::None` as Error with context |
| 9 | +pub trait NoneErrorContext<T> { |
| 10 | + /// Convert Option to Result by annotating what None means |
| 11 | + /// |
| 12 | + /// # Examples |
| 13 | + /// |
| 14 | + /// ```rust |
| 15 | + /// # extern crate quicli; |
| 16 | + /// # use quicli::prelude::*; |
| 17 | + /// # fn main() { assert!(run().is_err()); } |
| 18 | + /// # fn run() -> Result<()> { |
| 19 | + /// let xs = vec!["lorem", "ipsum"]; |
| 20 | + /// let x = xs.get(66); // will return None |
| 21 | + /// let result = x.none_means("index not found")?; |
| 22 | + /// # Ok(()) } |
| 23 | + /// ``` |
| 24 | + fn none_means<E: Display + Debug + Sync + Send + 'static>(self, explanation: E) -> Result<T>; |
| 25 | +} |
| 26 | + |
| 27 | +impl<T> NoneErrorContext<T> for Option<T> { |
| 28 | + fn none_means<E: Display + Debug + Sync + Send + 'static>(self, explanation: E) -> Result<T> { |
| 29 | + match self { |
| 30 | + Some(x) => Ok(x), |
| 31 | + None => Err(err_msg(explanation)), |
| 32 | + } |
| 33 | + } |
| 34 | +} |
| 35 | + |
| 36 | +#[cfg(test)] |
| 37 | +mod tests { |
| 38 | + #[test] |
| 39 | + fn none_means_error_message() { |
| 40 | + use prelude::*; |
| 41 | + run().unwrap(); |
| 42 | + |
| 43 | + fn run() -> Result<()> { |
| 44 | + let xs = vec!["lorem", "ipsum"]; |
| 45 | + let x = xs.get(66); // will return None |
| 46 | + |
| 47 | + let result = x.none_means("index not found"); |
| 48 | + |
| 49 | + assert!(result.is_err()); |
| 50 | + if let Err(error) = result { |
| 51 | + assert_eq!(error.to_string(), "index not found".to_string()); |
| 52 | + } |
| 53 | + |
| 54 | + Ok(()) |
| 55 | + } |
| 56 | + } |
| 57 | +} |
0 commit comments