Skip to main content

bash_interop/
failure.rs

1//! One error for anything that stops a piece of work: what was being done,
2//! and what went wrong underneath.
3
4use std::error::Error;
5use std::fmt;
6
7type Cause = Box<dyn Error + Send + Sync>;
8
9/// A context and a cause rather than an enum, since every use is `Display`
10/// or `source()`.
11#[derive(Debug)]
12pub struct Failure {
13    doing: String,
14    cause: Cause,
15}
16
17impl Failure {
18    pub fn new(doing: impl Into<String>, cause: impl Into<Cause>) -> Self {
19        Self {
20            doing: doing.into(),
21            cause: cause.into(),
22        }
23    }
24}
25
26impl fmt::Display for Failure {
27    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
28        write!(f, "{}: {}", self.doing, self.cause)
29    }
30}
31
32impl Error for Failure {
33    fn source(&self) -> Option<&(dyn Error + 'static)> {
34        Some(&*self.cause)
35    }
36}
37
38/// Says what was being attempted when a `Result` went wrong.
39pub trait Doing<T> {
40    fn doing(self, what: impl FnOnce() -> String) -> Result<T, Failure>;
41}
42
43impl<T, E: Into<Cause>> Doing<T> for Result<T, E> {
44    fn doing(self, what: impl FnOnce() -> String) -> Result<T, Failure> {
45        self.map_err(|cause| Failure::new(what(), cause))
46    }
47}