use std::fmt;
use thiserror::Error;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct SourceLocation {
pub file: String,
pub line: usize,
pub column: usize,
}
impl fmt::Display for SourceLocation {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}:{}:{}", self.file, self.line, self.column)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Diagnostic {
pub location: Option<SourceLocation>,
pub message: String,
pub hints: Vec<String>,
pub trace: Vec<SourceLocation>,
}
impl fmt::Display for Diagnostic {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match &self.location {
Some(loc) => write!(f, "{loc}: error: {}", self.message)?,
None => write!(f, "error: {}", self.message)?,
}
for hint in &self.hints {
write!(f, "\n hint: {hint}")?;
}
for site in &self.trace {
write!(f, "\n called from: {site}")?;
}
Ok(())
}
}
fn format_diagnostics(diagnostics: &[Diagnostic]) -> String {
diagnostics
.iter()
.map(|d| d.to_string())
.collect::<Vec<_>>()
.join("\n")
}
#[derive(Error, Debug)]
pub enum Error {
#[error("entry file not found: {0}")]
EntryNotFound(&'static str),
#[error("entry file is not valid UTF-8")]
InvalidUtf8,
#[error("compilation failed:\n{}", format_diagnostics(.0))]
Compilation(Vec<Diagnostic>),
#[error("PDF generation failed: {0}")]
PdfGeneration(String),
#[error("PNG encoding failed: {0}")]
PngEncoding(String),
#[error("invalid file path: {0}")]
InvalidFilePath(String),
#[error("invalid page selection: {0}")]
InvalidPageSelection(String),
#[error("invalid PDF config: {0}")]
InvalidPdfConfig(String),
#[error("decompression failed")]
Decompression(#[from] std::io::Error),
}
pub type Result<T> = std::result::Result<T, Error>;