1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
use scanlex::ScanError;
use std::error::Error;
use std::fmt;

#[derive(Debug)]
pub struct DateError {
    details: String,
}

impl fmt::Display for DateError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.details)
    }
}

impl Error for DateError {}

pub type DateResult<T> = Result<T, DateError>;

pub fn date_error(msg: &str) -> DateError {
    DateError {
        details: msg.into(),
    }
}

pub fn date_result<T>(msg: &str) -> DateResult<T> {
    Err(date_error(msg).into())
}

impl From<ScanError> for DateError {
    fn from(err: ScanError) -> DateError {
        date_error(&err.to_string())
    }
}

/// This trait maps optional values onto `DateResult`
pub trait OrErr<T> {
    /// use when the error message is always a simple string
    fn or_err(self, msg: &str) -> DateResult<T>;

    /// use when the message needs to be constructed
    fn or_then_err<C: FnOnce() -> String>(self, fun: C) -> DateResult<T>;
}

impl<T> OrErr<T> for Option<T> {
    fn or_err(self, msg: &str) -> DateResult<T> {
        self.ok_or(date_error(msg))
    }

    fn or_then_err<C: FnOnce() -> String>(self, fun: C) -> DateResult<T> {
        self.ok_or_else(|| date_error(&fun()))
    }
}