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_note<T: Into<String>>(&mut self, msg: T);
60 fn add_info<T: Into<String>>(&mut self, msg: T);
61 fn add_warning<T: Into<String>>(&mut self, msg: T);
62 fn add_error<T: Into<String>>(&mut self, msg: T);
63}
64
65#[derive(Clone, Debug)]
69pub struct PrintLog {
70 num_notes: usize,
71 num_infos: usize,
72 num_warnings: usize,
73 num_errors: usize
74}
75
76impl PrintLog {
77 pub fn new() -> PrintLog {
78 PrintLog { num_notes: 0, num_infos: 0, num_warnings: 0, num_errors: 0}
79 }
80}
81
82impl Default for PrintLog {
83 fn default() -> Self {
84 Self::new()
85 }
86}
87
88impl LogStatus for PrintLog {
89 fn num_notes(&self) -> usize {
90 self.num_notes
91 }
92
93 fn num_infos(&self) -> usize {
94 self.num_infos
95 }
96
97 fn num_warnings(&self) -> usize {
98 self.num_warnings
99 }
100
101 fn num_errors(&self) -> usize {
102 self.num_errors
103 }
104}
105
106impl Logger for PrintLog {
107 fn add_note<T: Into<String>>(&mut self, msg: T) {
108 eprintln!("NOTE: {}", msg.into());
109 }
110
111 fn add_info<T: Into<String>>(&mut self, msg: T) {
112 eprintln!("INFO: {}", msg.into());
113 }
114
115 fn add_warning<T: Into<String>>(&mut self, msg: T) {
116 eprintln!("WARNING: {}", msg.into());
117 }
118
119 fn add_error<T: Into<String>>(&mut self, msg: T) {
120 eprintln!("ERROR: {}", msg.into());
121 }
122}
123
124#[derive(Clone, Debug)]
127pub enum LogMsg { NoLogStore, Note(String), Info(String), Warning(String), Error(String) }
128
129impl LogMsg {
130 pub fn get_inner_str(&self) -> &str {
131 match self {
132 LogMsg::NoLogStore => "The log messages were not stored",
133 LogMsg::Note(s)
134 | LogMsg::Info(s)
135 | LogMsg::Warning(s)
136 | LogMsg::Error(s) => s.as_str()
137 }
138 }
139}
140impl Display for LogMsg {
141 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
142 match self {
143 LogMsg::NoLogStore => write!(f, "{}", self.get_inner_str()),
144 LogMsg::Note(s) => write!(f, "Note : {s}"),
145 LogMsg::Info(s) => write!(f, "Info : {s}"),
146 LogMsg::Warning(s) => write!(f, "Warning: {s}"),
147 LogMsg::Error(s) => write!(f, "ERROR : {s}"),
148 }
149 }
150}
151#[derive(Clone, Debug)]
153pub struct BufLog {
154 messages: Vec<LogMsg>,
155 num_notes: usize,
156 num_infos: usize,
157 num_warnings: usize,
158 num_errors: usize
159}
160
161impl BufLog {
162 pub fn new() -> Self {
163 BufLog { messages: Vec::new(), num_notes: 0, num_infos: 0, num_warnings: 0, num_errors: 0 }
164 }
165
166 pub fn is_empty(&self) -> bool {
167 self.messages.is_empty()
168 }
169
170 pub fn clear(&mut self) {
172 self.messages.clear();
173 self.num_notes = 0;
174 self.num_infos = 0;
175 self.num_warnings = 0;
176 self.num_errors = 0;
177 }
178
179 pub fn extend(&mut self, other: BufLog) {
181 self.num_notes += other.num_notes;
182 self.num_infos += other.num_infos;
183 self.num_warnings += other.num_warnings;
184 self.num_errors += other.num_errors;
185 self.messages.extend(other.messages)
186 }
187
188 pub fn extend_messages<T: IntoIterator<Item = LogMsg>>(&mut self, iter: T) {
189 self.messages.extend(iter.into_iter().inspect(|m| {
190 match m {
191 LogMsg::NoLogStore => {}
192 LogMsg::Note(_) => self.num_notes += 1,
193 LogMsg::Info(_) => self.num_infos += 1,
194 LogMsg::Warning(_) => self.num_warnings += 1,
195 LogMsg::Error(_) => self.num_errors += 1,
196 }
197 }));
198
199 }
200}
201
202impl LogStatus for BufLog {
203 fn num_notes(&self) -> usize {
204 self.num_notes
205 }
206
207 fn num_infos(&self) -> usize {
208 self.num_infos
209 }
210
211 fn num_warnings(&self) -> usize {
212 self.num_warnings
213 }
214
215 fn num_errors(&self) -> usize {
216 self.num_errors
217 }
218
219 fn get_messages(&self) -> impl Iterator<Item = &LogMsg> {
220 self.messages.iter()
221 }
222
223 fn get_messages_str(&self) -> String {
224 self.get_messages().map(|m| format!("- {m}")).collect::<Vec<_>>().join("\n")
225 }
226
227}
228
229impl Logger for BufLog {
230 fn add_note<T: Into<String>>(&mut self, msg: T) {
231 self.messages.push(LogMsg::Note(msg.into()));
232 self.num_notes += 1;
233 }
234
235 fn add_info<T: Into<String>>(&mut self, msg: T) {
236 self.messages.push(LogMsg::Info(msg.into()));
237 self.num_infos += 1;
238 }
239
240 fn add_warning<T: Into<String>>(&mut self, msg: T) {
241 self.messages.push(LogMsg::Warning(msg.into()));
242 self.num_warnings += 1;
243 }
244
245 fn add_error<T: Into<String>>(&mut self, msg: T) {
246 self.messages.push(LogMsg::Error(msg.into()));
247 self.num_errors += 1;
248 }
249}
250
251impl Default for BufLog {
252 fn default() -> Self {
253 BufLog::new()
254 }
255}
256
257impl Display for BufLog {
258 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
259 writeln!(f, "{}", self.get_messages_str())?;
260 writeln!(f, "{}", self.get_totals())
261 }
262}
263
264pub trait LogReader {
268 type Item: LogStatus;
269
270 fn get_log(&self) -> &Self::Item;
271
272 fn give_log(self) -> Self::Item;
273}
274
275pub trait LogWriter {
276 fn get_log_mut(&mut self) -> &mut impl Logger;
277}
278
279impl<T: LogReader + Debug> LogStatus for T {
280 fn num_notes(&self) -> usize {
281 self.get_log().num_notes()
282 }
283
284 fn num_infos(&self) -> usize {
285 self.get_log().num_infos()
286 }
287
288 fn num_warnings(&self) -> usize {
289 self.get_log().num_warnings()
290 }
291
292 fn num_errors(&self) -> usize {
293 self.get_log().num_errors()
294 }
295
296 fn has_no_errors(&self) -> bool {
297 self.get_log().has_no_errors()
298 }
299
300 fn has_no_warnings(&self) -> bool {
301 self.get_log().has_no_warnings()
302 }
303
304 fn get_messages(&self) -> impl Iterator<Item=&LogMsg> {
305 self.get_log().get_messages()
306 }
307
308 fn get_messages_str(&self) -> String {
309 self.get_log().get_messages_str()
310 }
311}
312
313impl<L: LogWriter + Debug> Logger for L {
314 fn add_note<T: Into<String>>(&mut self, msg: T) {
315 self.get_log_mut().add_note(msg);
316 }
317
318 fn add_info<T: Into<String>>(&mut self, msg: T) {
319 self.get_log_mut().add_info(msg);
320 }
321
322 fn add_warning<T: Into<String>>(&mut self, msg: T) {
323 self.get_log_mut().add_warning(msg);
324 }
325
326 fn add_error<T: Into<String>>(&mut self, msg: T) {
327 self.get_log_mut().add_error(msg);
328 }
329}
330
331