1use std::fmt;
4
5use thiserror::Error;
6
7#[derive(Debug, Clone, PartialEq, Eq)]
12pub struct SourceLocation {
13 pub file: String,
15 pub line: usize,
17 pub column: usize,
19}
20
21impl fmt::Display for SourceLocation {
22 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
23 write!(f, "{}:{}:{}", self.file, self.line, self.column)
24 }
25}
26
27#[derive(Debug, Clone, PartialEq, Eq)]
29pub struct Diagnostic {
30 pub location: Option<SourceLocation>,
32 pub message: String,
34 pub hints: Vec<String>,
36 pub trace: Vec<SourceLocation>,
38}
39
40impl fmt::Display for Diagnostic {
41 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
42 match &self.location {
43 Some(loc) => write!(f, "{loc}: error: {}", self.message)?,
44 None => write!(f, "error: {}", self.message)?,
45 }
46 for hint in &self.hints {
47 write!(f, "\n hint: {hint}")?;
48 }
49 for site in &self.trace {
50 write!(f, "\n called from: {site}")?;
51 }
52 Ok(())
53 }
54}
55
56fn format_diagnostics(diagnostics: &[Diagnostic]) -> String {
58 diagnostics
59 .iter()
60 .map(|d| d.to_string())
61 .collect::<Vec<_>>()
62 .join("\n")
63}
64
65#[derive(Error, Debug)]
67pub enum Error {
68 #[error("entry file not found: {0}")]
70 EntryNotFound(&'static str),
71
72 #[error("entry file is not valid UTF-8")]
74 InvalidUtf8,
75
76 #[error("compilation failed:\n{}", format_diagnostics(.0))]
78 Compilation(Vec<Diagnostic>),
79
80 #[error("PDF generation failed: {0}")]
82 PdfGeneration(String),
83
84 #[error("PNG encoding failed: {0}")]
86 PngEncoding(String),
87
88 #[error("invalid file path: {0}")]
90 InvalidFilePath(String),
91
92 #[error("invalid page selection: {0}")]
94 InvalidPageSelection(String),
95
96 #[error("invalid PDF config: {0}")]
98 InvalidPdfConfig(String),
99
100 #[error("decompression failed")]
102 Decompression(#[from] std::io::Error),
103}
104
105pub type Result<T> = std::result::Result<T, Error>;