1use std::fmt;
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq)]
12pub enum Severity {
13 Error,
15 Warning,
17}
18
19impl fmt::Display for Severity {
20 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
21 match self {
22 Severity::Error => f.write_str("error"),
23 Severity::Warning => f.write_str("warning"),
24 }
25 }
26}
27
28#[derive(Debug, Clone, PartialEq, Eq)]
30pub struct Diagnostic {
31 pub rule: &'static str,
32 pub severity: Severity,
33 pub message: String,
34 pub pos: Option<(u32, u32)>,
35}
36
37impl Diagnostic {
38 pub fn new(
39 rule: &'static str,
40 severity: Severity,
41 pos: Option<(u32, u32)>,
42 message: impl Into<String>,
43 ) -> Self {
44 Self {
45 rule,
46 severity,
47 message: message.into(),
48 pos,
49 }
50 }
51
52 pub fn error(rule: &'static str, pos: Option<(u32, u32)>, message: impl Into<String>) -> Self {
53 Self::new(rule, Severity::Error, pos, message)
54 }
55
56 pub fn warning(
57 rule: &'static str,
58 pos: Option<(u32, u32)>,
59 message: impl Into<String>,
60 ) -> Self {
61 Self::new(rule, Severity::Warning, pos, message)
62 }
63
64 pub fn line(&self) -> Option<u32> {
66 self.pos.map(|(line, _)| line)
67 }
68
69 pub fn column(&self) -> Option<u32> {
71 self.pos.map(|(_, col)| col)
72 }
73}
74
75impl fmt::Display for Diagnostic {
76 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
77 match self.pos {
78 Some((line, col)) => write!(
79 f,
80 "{sev} [{rule}] {line}:{col}: {msg}",
81 sev = self.severity,
82 rule = self.rule,
83 msg = self.message,
84 ),
85 None => write!(
86 f,
87 "{sev} [{rule}]: {msg}",
88 sev = self.severity,
89 rule = self.rule,
90 msg = self.message,
91 ),
92 }
93 }
94}