mod builder;
pub use builder::Builder;
use nonempty::NonEmpty;
use serde::Deserialize;
use serde::Serialize;
use crate::concern::Code;
use crate::display;
use crate::file::Location;
#[derive(Clone, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
pub struct Failure {
code: Code,
locations: NonEmpty<Location>,
subject: String,
body: String,
fix: Option<String>,
}
impl Failure {
pub fn code(&self) -> &Code {
&self.code
}
pub fn locations(&self) -> &NonEmpty<Location> {
&self.locations
}
pub fn subject(&self) -> &str {
self.subject.as_str()
}
pub fn body(&self) -> &str {
self.body.as_str()
}
pub fn fix(&self) -> Option<&str> {
self.fix.as_deref()
}
pub fn display(&self, f: &mut impl std::fmt::Write, mode: display::Mode) -> std::fmt::Result {
match mode {
display::Mode::OneLine => display_one_line(self, f),
display::Mode::Full => display_full(self, f),
}
}
}
fn display_one_line(error: &Failure, f: &mut impl std::fmt::Write) -> std::fmt::Result {
write!(f, "[{}] {}", error.code, error.subject)?;
let locations = error
.locations
.iter()
.flat_map(|location| location.to_string())
.collect::<Vec<_>>();
if !locations.is_empty() {
write!(f, " ({})", locations.join(", "))?;
}
Ok(())
}
fn display_full(error: &Failure, f: &mut impl std::fmt::Write) -> std::fmt::Result {
display_one_line(error, f)?;
write!(f, "\n\n{}", error.body)?;
if let Some(fix) = error.fix() {
write!(f, "\n\nTo fix this error, {}", fix.to_ascii_lowercase())?;
}
Ok(())
}
impl std::fmt::Display for Failure {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.display(f, display::Mode::OneLine)
}
}
impl std::error::Error for Failure {}
pub type Result = std::result::Result<(), Vec<Failure>>;
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn display() -> std::result::Result<(), Box<dyn std::error::Error>> {
let code = Code::try_new(crate::concern::code::Kind::Error, crate::Version::V1, 1)?;
let error = Builder::default()
.code(code)
.push_location(Location::Unplaced)
.subject("Hello, world!")
.body("A body.")
.fix("How to fix the issue.")
.try_build()?;
assert_eq!(error.to_string(), "[v1::E001] Hello, world!");
Ok(())
}
}