Skip to main content

yui_core/util/
parse_err.rs

1//! [`ParseErr`]: the `FromStr::Err` of every math type in this crate.
2
3use std::error::Error;
4use std::fmt::{Display, Formatter, Result as FmtResult};
5
6/// Failure to parse a math object from its string form. The message is carried
7/// privately so variants can be added later without breaking the public API.
8#[derive(Debug, Clone, PartialEq, Eq)]
9pub struct ParseErr {
10    msg: String,
11}
12
13impl ParseErr {
14    pub fn new(msg: impl Into<String>) -> Self {
15        Self { msg: msg.into() }
16    }
17
18    /// The standard form: `cannot parse "{input}" as {target}`.
19    pub fn invalid(input: &str, target: &str) -> Self {
20        Self::new(format!("cannot parse \"{input}\" as {target}"))
21    }
22
23    pub fn msg(&self) -> &str {
24        &self.msg
25    }
26}
27
28impl Display for ParseErr {
29    fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
30        write!(f, "{}", self.msg)
31    }
32}
33
34impl Error for ParseErr {}
35
36#[cfg(test)]
37mod tests {
38    use super::*;
39
40    #[test]
41    fn invalid_names_the_input_and_the_target() {
42        let e = ParseErr::invalid("1/0", "Q");
43        assert_eq!(e.to_string(), "cannot parse \"1/0\" as Q");
44        assert_eq!(e.msg(), e.to_string());
45    }
46
47    #[test]
48    fn is_a_std_error() {
49        fn takes_err<E: Error>(_: E) {}
50        takes_err(ParseErr::new("boom"));
51
52        // the point of the newtype: `?` into a `dyn Error` chain, which `String` cannot do.
53        fn f() -> Result<(), Box<dyn Error>> {
54            Err(ParseErr::new("boom"))?
55        }
56        assert_eq!(f().unwrap_err().to_string(), "boom");
57    }
58}