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_infos(&self) -> usize;
12 fn num_warnings(&self) -> usize;
13 fn num_errors(&self) -> usize;
14 #[inline]
15 fn has_no_errors(&self) -> bool {
16 self.num_errors() == 0
17 }
18 #[inline]
19 fn has_no_warnings(&self) -> bool {
20 self.num_warnings() == 0
21 }
22
23 fn get_messages(&self) -> impl Iterator<Item = &LogMsg> {
24 [&NO_LOG_STORE].into_iter() }
26
27 fn get_messages_str(&self) -> String {
28 self.get_messages().map(|m| format!("- {m}")).collect::<Vec<_>>().join("\n")
29 }
30
31 fn get_notes(&self) -> impl Iterator<Item = &LogMsg> {
32 self.get_messages().filter(|m| matches!(m, LogMsg::Note(_)))
33 }
34
35 fn get_infos(&self) -> impl Iterator<Item = &LogMsg> {
36 self.get_messages().filter(|m| matches!(m, LogMsg::Info(_)))
37 }
38
39 fn get_warnings(&self) -> impl Iterator<Item = &LogMsg> {
40 self.get_messages().filter(|m| matches!(m, LogMsg::Warning(_)))
41 }
42
43 fn get_errors(&self) -> impl Iterator<Item = &LogMsg> {
44 self.get_messages().filter(|m| matches!(m, LogMsg::Error(_)))
45 }
46
47 fn get_totals(&self) -> String {
48 format!(
49 "{} note(s)\n{} info(s)\n{} warning(s)\n{} error(s)",
50 self.num_notes(),
51 self.num_infos(),
52 self.num_warnings(),
53 self.num_errors())
54 }
55}
56
57pub trait Logger: Debug {
59 fn add(&mut self, msg: LogMsg) {
60 match msg {
61 LogMsg::NoLogStore => {}
62 LogMsg::Note(s) => self.add_note(s),
63 LogMsg::Info(s) => self.add_info(s),
64 LogMsg::Warning(s) => self.add_warning(s),
65 LogMsg::Error(s) => self.add_error(s),
66 }
67 }
68 fn add_note<T: Into<String>>(&mut self, msg: T);
69 fn add_info<T: Into<String>>(&mut self, msg: T);
70 fn add_warning<T: Into<String>>(&mut self, msg: T);
71 fn add_error<T: Into<String>>(&mut self, msg: T);
72}
73
74#[derive(Clone, Debug)]
78pub struct PrintLog {
79 num_notes: usize,
80 num_infos: usize,
81 num_warnings: usize,
82 num_errors: usize
83}
84
85impl PrintLog {
86 pub fn new() -> PrintLog {
87 PrintLog { num_notes: 0, num_infos: 0, num_warnings: 0, num_errors: 0}
88 }
89}
90
91impl Default for PrintLog {
92 fn default() -> Self {
93 Self::new()
94 }
95}
96
97impl LogStatus for PrintLog {
98 fn num_notes(&self) -> usize {
99 self.num_notes
100 }
101
102 fn num_infos(&self) -> usize {
103 self.num_infos
104 }
105
106 fn num_warnings(&self) -> usize {
107 self.num_warnings
108 }
109
110 fn num_errors(&self) -> usize {
111 self.num_errors
112 }
113}
114
115impl Logger for PrintLog {
116 fn add_note<T: Into<String>>(&mut self, msg: T) {
117 eprintln!("NOTE: {}", msg.into());
118 }
119
120 fn add_info<T: Into<String>>(&mut self, msg: T) {
121 eprintln!("INFO: {}", msg.into());
122 }
123
124 fn add_warning<T: Into<String>>(&mut self, msg: T) {
125 eprintln!("WARNING: {}", msg.into());
126 }
127
128 fn add_error<T: Into<String>>(&mut self, msg: T) {
129 eprintln!("ERROR: {}", msg.into());
130 }
131}
132
133#[derive(Clone, Debug)]
136pub enum LogMsg { NoLogStore, Note(String), Info(String), Warning(String), Error(String) }
137
138impl LogMsg {
139 pub fn get_inner_str(&self) -> &str {
140 match self {
141 LogMsg::NoLogStore => "The log messages were not stored",
142 LogMsg::Note(s)
143 | LogMsg::Info(s)
144 | LogMsg::Warning(s)
145 | LogMsg::Error(s) => s.as_str()
146 }
147 }
148
149 pub fn get_inner_str_mut(&mut self) -> Option<&mut String> {
150 match self {
151 LogMsg::NoLogStore => None,
152 LogMsg::Note(s)
153 | LogMsg::Info(s)
154 | LogMsg::Warning(s)
155 | LogMsg::Error(s) => Some(s),
156 }
157 }
158}
159
160impl Display for LogMsg {
161 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
162 match self {
163 LogMsg::NoLogStore => write!(f, "{}", self.get_inner_str()),
164 LogMsg::Note(s) => write!(f, "Note : {s}"),
165 LogMsg::Info(s) => write!(f, "Info : {s}"),
166 LogMsg::Warning(s) => write!(f, "Warning: {s}"),
167 LogMsg::Error(s) => write!(f, "ERROR : {s}"),
168 }
169 }
170}
171
172#[derive(Clone, Debug)]
174pub struct BufLog {
175 messages: Vec<LogMsg>,
176 num_notes: usize,
177 num_infos: usize,
178 num_warnings: usize,
179 num_errors: usize
180}
181
182impl BufLog {
183 pub fn new() -> Self {
184 BufLog { messages: Vec::new(), num_notes: 0, num_infos: 0, num_warnings: 0, num_errors: 0 }
185 }
186
187 pub fn is_empty(&self) -> bool {
188 self.messages.is_empty()
189 }
190
191 pub fn clear(&mut self) {
193 self.messages.clear();
194 self.num_notes = 0;
195 self.num_infos = 0;
196 self.num_warnings = 0;
197 self.num_errors = 0;
198 }
199
200 pub fn extend(&mut self, other: BufLog) {
202 self.num_notes += other.num_notes;
203 self.num_infos += other.num_infos;
204 self.num_warnings += other.num_warnings;
205 self.num_errors += other.num_errors;
206 self.messages.extend(other.messages)
207 }
208
209 pub fn extend_messages<T: IntoIterator<Item = LogMsg>>(&mut self, iter: T) {
210 self.messages.extend(iter.into_iter().inspect(|m| {
211 match m {
212 LogMsg::NoLogStore => {}
213 LogMsg::Note(_) => self.num_notes += 1,
214 LogMsg::Info(_) => self.num_infos += 1,
215 LogMsg::Warning(_) => self.num_warnings += 1,
216 LogMsg::Error(_) => self.num_errors += 1,
217 }
218 }));
219
220 }
221}
222
223impl LogStatus for BufLog {
224 fn num_notes(&self) -> usize {
225 self.num_notes
226 }
227
228 fn num_infos(&self) -> usize {
229 self.num_infos
230 }
231
232 fn num_warnings(&self) -> usize {
233 self.num_warnings
234 }
235
236 fn num_errors(&self) -> usize {
237 self.num_errors
238 }
239
240 fn get_messages(&self) -> impl Iterator<Item = &LogMsg> {
241 self.messages.iter()
242 }
243
244 fn get_messages_str(&self) -> String {
245 self.get_messages().map(|m| format!("- {m}")).collect::<Vec<_>>().join("\n")
246 }
247
248}
249
250impl Logger for BufLog {
251 fn add(&mut self, msg: LogMsg) {
252 match &msg {
253 LogMsg::NoLogStore => {}
254 LogMsg::Note(_) => { self.num_notes += 1; }
255 LogMsg::Info(_) => { self.num_infos += 1; }
256 LogMsg::Warning(_) => { self.num_warnings += 1; }
257 LogMsg::Error(_) => { self.num_errors += 1; }
258 }
259 self.messages.push(msg);
260 }
261
262 fn add_note<T: Into<String>>(&mut self, msg: T) {
263 self.messages.push(LogMsg::Note(msg.into()));
264 self.num_notes += 1;
265 }
266
267 fn add_info<T: Into<String>>(&mut self, msg: T) {
268 self.messages.push(LogMsg::Info(msg.into()));
269 self.num_infos += 1;
270 }
271
272 fn add_warning<T: Into<String>>(&mut self, msg: T) {
273 self.messages.push(LogMsg::Warning(msg.into()));
274 self.num_warnings += 1;
275 }
276
277 fn add_error<T: Into<String>>(&mut self, msg: T) {
278 self.messages.push(LogMsg::Error(msg.into()));
279 self.num_errors += 1;
280 }
281}
282
283impl Default for BufLog {
284 fn default() -> Self {
285 BufLog::new()
286 }
287}
288
289impl Display for BufLog {
290 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
291 writeln!(f, "{}", self.get_messages_str())?;
292 writeln!(f, "{}", self.get_totals())
293 }
294}
295
296pub trait LogReader {
300 type Item: LogStatus;
301
302 fn get_log(&self) -> &Self::Item;
303
304 fn give_log(self) -> Self::Item;
305}
306
307pub trait LogWriter {
308 fn get_log_mut(&mut self) -> &mut impl Logger;
309}
310
311impl<T: LogReader + Debug> LogStatus for T {
312 fn num_notes(&self) -> usize {
313 self.get_log().num_notes()
314 }
315
316 fn num_infos(&self) -> usize {
317 self.get_log().num_infos()
318 }
319
320 fn num_warnings(&self) -> usize {
321 self.get_log().num_warnings()
322 }
323
324 fn num_errors(&self) -> usize {
325 self.get_log().num_errors()
326 }
327
328 fn has_no_errors(&self) -> bool {
329 self.get_log().has_no_errors()
330 }
331
332 fn has_no_warnings(&self) -> bool {
333 self.get_log().has_no_warnings()
334 }
335
336 fn get_messages(&self) -> impl Iterator<Item=&LogMsg> {
337 self.get_log().get_messages()
338 }
339
340 fn get_messages_str(&self) -> String {
341 self.get_log().get_messages_str()
342 }
343}
344
345impl<L: LogWriter + Debug> Logger for L {
346 fn add(&mut self, msg: LogMsg) {
347 self.get_log_mut().add(msg);
348 }
349
350 fn add_note<T: Into<String>>(&mut self, msg: T) {
351 self.get_log_mut().add_note(msg);
352 }
353
354 fn add_info<T: Into<String>>(&mut self, msg: T) {
355 self.get_log_mut().add_info(msg);
356 }
357
358 fn add_warning<T: Into<String>>(&mut self, msg: T) {
359 self.get_log_mut().add_warning(msg);
360 }
361
362 fn add_error<T: Into<String>>(&mut self, msg: T) {
363 self.get_log_mut().add_error(msg);
364 }
365}
366
367