microcad_lang_base/diag/
diagnostics.rs1use std::slice::Iter;
5
6use crate::{GetSourceLocInfoByHash, diag::*};
7
8#[derive(Debug, Default, Clone)]
10pub struct Diagnostics {
11 error_count: u32,
13 warning_count: u32,
15 diagnostics: Vec<Diagnostic>,
17}
18
19impl Diagnostics {
20 pub fn has_errors(&self) -> bool {
21 self.error_count > 0
22 }
23
24 pub fn has_warnings(&self) -> bool {
25 self.warning_count > 0
26 }
27
28 pub fn iter(&'_ self) -> Iter<'_, Diagnostic> {
29 self.diagnostics.iter()
30 }
31
32 pub fn clear(&mut self) {
34 self.diagnostics.clear();
35 self.error_count = 0;
36 self.warning_count = 0;
37 }
38
39 pub fn pretty_print(
41 &self,
42 f: &mut dyn std::fmt::Write,
43 source_by_hash: &impl GetSourceLocInfoByHash,
44 options: &DiagRenderOptions,
45 ) -> std::fmt::Result {
46 self.diagnostics
47 .iter()
48 .try_for_each(|diag| diag.pretty_print(f, source_by_hash, options))
49 }
50
51 pub fn append(&mut self, mut other: Diagnostics) {
53 self.error_count += other.error_count;
54 self.warning_count += other.warning_count;
55 self.diagnostics.append(&mut other.diagnostics);
56 }
57
58 pub fn warning_count(&self) -> u32 {
60 self.warning_count
61 }
62
63 pub fn error_count(&self) -> u32 {
65 self.error_count
66 }
67
68 pub fn error_lines(&self) -> HashSet<u32> {
70 self.iter()
71 .filter_map(|d| {
72 if d.level() == Level::Error {
73 d.src_ref().line()
74 } else {
75 None
76 }
77 })
78 .collect()
79 }
80
81 pub fn warning_lines(&self) -> HashSet<u32> {
83 self.iter()
84 .filter_map(|d| {
85 if d.level() == Level::Warning {
86 d.src_ref().line()
87 } else {
88 None
89 }
90 })
91 .collect()
92 }
93}
94
95impl<R> From<R> for Diagnostics
96where
97 R: Into<Report>,
98{
99 fn from(report: R) -> Self {
100 Self {
101 error_count: 1,
102 warning_count: 0,
103 diagnostics: vec![Diagnostic::Error(std::rc::Rc::new(Refer::none(
104 report.into(),
105 )))],
106 }
107 }
108}
109
110impl FromIterator<Diagnostics> for Diagnostics {
111 fn from_iter<I: IntoIterator<Item = Diagnostics>>(iter: I) -> Self {
112 let mut root = Diagnostics::default();
113 for other in iter {
114 root.append(other);
115 }
116 root
117 }
118}
119
120impl PushDiag for Diagnostics {
121 fn push_diag(&mut self, diag: Diagnostic) -> DiagResult<()> {
122 match &diag {
123 Diagnostic::Error(_) => {
124 self.error_count += 1;
125 }
126 Diagnostic::Warning(_) => {
127 self.warning_count += 1;
128 }
129 _ => (),
130 }
131
132 self.diagnostics.push(diag);
133 Ok(())
134 }
135}