1use std::fmt::{Debug, Display, Formatter};
4static NO_LOG_STORE: LogMsg = LogMsg::NoLogStore;
7
8pub trait LogStatus: Debug {
10 fn num_notes(&self) -> usize;
11 fn num_warnings(&self) -> usize;
12 fn num_errors(&self) -> usize;
13 #[inline]
14 fn has_no_errors(&self) -> bool {
15 self.num_errors() == 0
16 }
17 #[inline]
18 fn has_no_warnings(&self) -> bool {
19 self.num_warnings() == 0
20 }
21
22 fn get_messages(&self) -> impl Iterator<Item = &LogMsg> {
23 [&NO_LOG_STORE].into_iter() }
25
26 fn get_messages_str(&self) -> String {
27 self.get_messages().map(|m| format!("- {m}")).collect::<Vec<_>>().join("\n")
28 }
29
30 fn get_notes(&self) -> impl Iterator<Item = &String> {
31 self.get_messages().filter_map(|m| if let LogMsg::Note(s) = m { Some(s) } else { None })
32 }
33
34 fn get_warnings(&self) -> impl Iterator<Item = &String> {
35 self.get_messages().filter_map(|m| if let LogMsg::Warning(s) = m { Some(s) } else { None })
36 }
37
38 fn get_errors(&self) -> impl Iterator<Item = &String> {
39 self.get_messages().filter_map(|m| if let LogMsg::Error(s) = m { Some(s) } else { None })
40 }
41}
42
43pub trait Logger: Debug {
45 fn add_note<T: Into<String>>(&mut self, msg: T);
46 fn add_warning<T: Into<String>>(&mut self, msg: T);
47 fn add_error<T: Into<String>>(&mut self, msg: T);
48}
49
50#[derive(Clone, Debug)]
54pub struct PrintLog {
55 num_notes: usize,
56 num_warnings: usize,
57 num_errors: usize
58}
59
60impl PrintLog {
61 pub fn new() -> PrintLog {
62 PrintLog { num_notes: 0, num_warnings: 0, num_errors: 0}
63 }
64}
65
66impl LogStatus for PrintLog {
67 fn num_notes(&self) -> usize {
68 self.num_notes
69 }
70
71 fn num_warnings(&self) -> usize {
72 self.num_warnings
73 }
74
75 fn num_errors(&self) -> usize {
76 self.num_errors
77 }
78}
79
80impl Logger for PrintLog {
81 fn add_note<T: Into<String>>(&mut self, msg: T) {
82 eprintln!("NOTE: {}", msg.into());
83 }
84
85 fn add_warning<T: Into<String>>(&mut self, msg: T) {
86 eprintln!("WARNING: {}", msg.into());
87 }
88
89 fn add_error<T: Into<String>>(&mut self, msg: T) {
90 eprintln!("ERROR: {}", msg.into());
91 }
92}
93
94#[derive(Clone, Debug)]
97pub enum LogMsg { NoLogStore, Note(String), Warning(String), Error(String) }
98
99impl Display for LogMsg {
100 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
101 match self {
102 LogMsg::NoLogStore => write!(f, "The log messages were not stored"),
103 LogMsg::Note(s) => write!(f, "Note : {s}"),
104 LogMsg::Warning(s) => write!(f, "Warning: {s}"),
105 LogMsg::Error(s) => write!(f, "ERROR : {s}"),
106 }
107 }
108}
109#[derive(Clone, Debug)]
111pub struct BufLog {
112 messages: Vec<LogMsg>,
113 num_notes: usize,
114 num_warnings: usize,
115 num_errors: usize
116}
117
118impl BufLog {
119 pub fn new() -> Self {
120 BufLog { messages: Vec::new(), num_notes: 0, num_warnings: 0, num_errors: 0 }
121 }
122
123 pub fn is_empty(&self) -> bool {
124 self.messages.is_empty()
125 }
126
127 pub fn clear(&mut self) {
129 self.messages.clear();
130 self.num_notes = 0;
131 self.num_warnings = 0;
132 self.num_errors = 0;
133 }
134
135 pub fn extend(&mut self, other: BufLog) {
137 self.num_notes += other.num_notes;
138 self.num_warnings += other.num_warnings;
139 self.num_errors += other.num_errors;
140 self.messages.extend(other.messages)
141 }
142
143 pub fn extend_messages<T: IntoIterator<Item = LogMsg>>(&mut self, iter: T) {
144 self.messages.extend(iter.into_iter().inspect(|m| {
145 match m {
146 LogMsg::NoLogStore => {}
147 LogMsg::Note(_) => self.num_notes += 1,
148 LogMsg::Warning(_) => self.num_warnings += 1,
149 LogMsg::Error(_) => self.num_errors += 1,
150 }
151 }));
152
153 }
154}
155
156impl LogStatus for BufLog {
157 fn num_notes(&self) -> usize {
158 self.num_notes
159 }
160
161 fn num_warnings(&self) -> usize {
162 self.num_warnings
163 }
164
165 fn num_errors(&self) -> usize {
166 self.num_errors
167 }
168
169 fn get_messages(&self) -> impl Iterator<Item = &LogMsg> {
170 self.messages.iter()
171 }
172
173 fn get_messages_str(&self) -> String {
174 self.get_messages().map(|m| format!("- {m}")).collect::<Vec<_>>().join("\n")
175 }
176
177}
178
179impl Logger for BufLog {
180 fn add_note<T: Into<String>>(&mut self, msg: T) {
181 self.messages.push(LogMsg::Note(msg.into()));
182 self.num_notes += 1;
183 }
184
185 fn add_warning<T: Into<String>>(&mut self, msg: T) {
186 self.messages.push(LogMsg::Warning(msg.into()));
187 self.num_warnings += 1;
188 }
189
190 fn add_error<T: Into<String>>(&mut self, msg: T) {
191 self.messages.push(LogMsg::Error(msg.into()));
192 self.num_errors += 1;
193 }
194}
195
196impl Default for BufLog {
197 fn default() -> Self {
198 BufLog::new()
199 }
200}
201
202impl Display for BufLog {
203 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
204 write!(f, "{}", self.get_messages_str())
205 }
206}
207
208pub trait LogReader {
212 type Item: LogStatus;
213
214 fn get_log(&self) -> &Self::Item;
215
216 fn give_log(self) -> Self::Item;
217}
218
219pub trait LogWriter {
220 fn get_mut_log(&mut self) -> &mut impl Logger;
221}
222
223impl<T: LogReader + Debug> LogStatus for T {
224 fn num_notes(&self) -> usize {
225 self.get_log().num_notes()
226 }
227
228 fn num_warnings(&self) -> usize {
229 self.get_log().num_warnings()
230 }
231
232 fn num_errors(&self) -> usize {
233 self.get_log().num_errors()
234 }
235
236 fn has_no_errors(&self) -> bool {
237 self.get_log().has_no_errors()
238 }
239
240 fn has_no_warnings(&self) -> bool {
241 self.get_log().has_no_warnings()
242 }
243
244 fn get_messages(&self) -> impl Iterator<Item=&LogMsg> {
245 self.get_log().get_messages()
246 }
247
248 fn get_messages_str(&self) -> String {
249 self.get_log().get_messages_str()
250 }
251}
252
253impl<L: LogWriter + Debug> Logger for L {
254 fn add_note<T: Into<String>>(&mut self, msg: T) {
255 self.get_mut_log().add_note(msg);
256 }
257
258 fn add_warning<T: Into<String>>(&mut self, msg: T) {
259 self.get_mut_log().add_warning(msg);
260 }
261
262 fn add_error<T: Into<String>>(&mut self, msg: T) {
263 self.get_mut_log().add_error(msg);
264 }
265}
266
267