duck_diagnostic/
diagnostic.rs1use std::fmt;
2
3#[derive(Debug, Clone, Copy, PartialEq, Eq)]
4pub enum Severity {
5 Error,
6 Warning,
7 Note,
8 Help,
9}
10
11pub trait DiagnosticCode: fmt::Debug + Clone {
38 fn code(&self) -> &str;
39 fn severity(&self) -> Severity;
40}
41
42#[derive(Debug, Clone, PartialEq, Eq)]
43pub struct Span {
44 pub file: String,
45 pub line: usize,
46 pub column: usize,
47 pub length: usize,
48}
49
50impl Span {
51 pub fn new(file: impl Into<String>, line: usize, column: usize, length: usize) -> Self {
52 Self { file: file.into(), line, column, length }
53 }
54}
55
56#[derive(Debug, Clone, Copy, PartialEq, Eq)]
57pub enum LabelStyle {
58 Primary,
59 Secondary,
60}
61
62#[derive(Debug, Clone)]
63pub struct Label {
64 pub span: Span,
65 pub message: Option<String>,
66 pub style: LabelStyle,
67}
68
69impl Label {
70 pub fn primary(span: Span, message: impl Into<Option<String>>) -> Self {
71 Self { span, message: message.into(), style: LabelStyle::Primary }
72 }
73
74 pub fn secondary(span: Span, message: impl Into<Option<String>>) -> Self {
75 Self { span, message: message.into(), style: LabelStyle::Secondary }
76 }
77}
78
79#[derive(Debug, Clone)]
80pub struct Diagnostic<C: DiagnosticCode> {
81 pub code: C,
82 pub severity: Severity,
83 pub message: String,
84 pub labels: Vec<Label>,
85 pub notes: Vec<String>,
86 pub help: Option<String>,
87}
88
89impl<C: DiagnosticCode> Diagnostic<C> {
90 pub fn new(code: C, message: impl Into<String>) -> Self {
91 let severity = code.severity();
92 Self {
93 code,
94 severity,
95 message: message.into(),
96 labels: Vec::new(),
97 notes: Vec::new(),
98 help: None,
99 }
100 }
101
102 pub fn with_label(mut self, label: Label) -> Self {
103 self.labels.push(label);
104 self
105 }
106
107 pub fn with_note(mut self, note: impl Into<String>) -> Self {
108 self.notes.push(note.into());
109 self
110 }
111
112 pub fn with_help(mut self, help: impl Into<String>) -> Self {
113 self.help = Some(help.into());
114 self
115 }
116}