use std::fmt;
#[derive(Debug, PartialEq, Eq)]
pub enum Error {
Parse {
message: String,
line: Option<u32>,
property: Option<String>,
},
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Parse {
message,
line,
property,
} => {
f.write_str("parse error")?;
if let Some(l) = line {
write!(f, " at line {l}")?;
}
if let Some(p) = property {
write!(f, " [{p}]")?;
}
write!(f, ": {message}")
}
}
}
}
impl std::error::Error for Error {}
impl Error {
pub fn parse(message: impl Into<String>) -> Self {
Self::Parse {
message: message.into(),
line: None,
property: None,
}
}
pub fn parse_at_line(line: u32, message: impl Into<String>) -> Self {
Self::Parse {
message: message.into(),
line: Some(line),
property: None,
}
}
pub fn parse_at(line: u32, property: impl Into<String>, message: impl Into<String>) -> Self {
Self::Parse {
message: message.into(),
line: Some(line),
property: Some(property.into()),
}
}
}
pub type Result<T> = std::result::Result<T, Error>;
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn display_without_line_or_property() {
let err = Error::parse("VEVENT missing DTSTAMP");
assert_eq!(err.to_string(), "parse error: VEVENT missing DTSTAMP");
}
#[test]
fn display_with_line_only() {
let err = Error::parse_at_line(42, "VEVENT missing DTSTAMP");
assert_eq!(
err.to_string(),
"parse error at line 42: VEVENT missing DTSTAMP"
);
}
#[test]
fn display_with_line_and_property() {
let err = Error::parse_at(42, "DTSTAMP", "Invalid value");
assert_eq!(
err.to_string(),
"parse error at line 42 [DTSTAMP]: Invalid value"
);
}
}