llguidance/
logging.rs

1use std::fmt::Write;
2
3pub struct Logger {
4    effective_level: u32,
5    buffer_level: u32,
6    stderr_level: u32,
7    buffer: String,
8}
9
10pub struct InfoLogger<'a> {
11    logger: &'a mut Logger,
12}
13
14pub struct WarningLogger<'a> {
15    logger: &'a mut Logger,
16}
17
18impl Clone for Logger {
19    fn clone(&self) -> Self {
20        Self {
21            effective_level: self.effective_level,
22            buffer_level: self.buffer_level,
23            stderr_level: self.stderr_level,
24            buffer: String::new(), // clean logs on clone
25        }
26    }
27}
28
29impl Logger {
30    // The buffer_level is used to determine the level of messages that are stored
31    // in a buffer in the sequence object. These can be read and sent back to the user
32    // over network etc. Note that some client libraries will look in these logs
33    // for return values from the parser. If you support sending these back, set it to 2.
34    //
35    // The stderr_level is just for printing stuff out on stderr.
36    // 0 - no output
37    // 1 - warnings only
38    // 2 - info output
39    pub fn new(buffer_level: u32, stderr_level: u32) -> Self {
40        Self {
41            buffer_level,
42            stderr_level,
43            effective_level: std::cmp::max(buffer_level, stderr_level),
44            buffer: String::new(),
45        }
46    }
47
48    pub fn warn(&mut self, s: &str) {
49        if self.level_enabled(1) {
50            self.write_warning("Warning: ");
51            self.write_warning(s);
52            self.write_warning("\n");
53        }
54    }
55
56    pub fn info(&mut self, s: &str) {
57        if self.level_enabled(2) {
58            self.write_info(s);
59            self.write_info("\n");
60        }
61    }
62
63    pub fn write_warning(&mut self, s: &str) {
64        self.write_level(1, s);
65    }
66
67    pub fn write_info(&mut self, s: &str) {
68        self.write_level(2, s);
69    }
70
71    pub fn write_buffer(&mut self, s: &str) {
72        self.buffer.push_str(s);
73    }
74
75    #[inline(always)]
76    pub fn write_level(&mut self, level: u32, s: &str) {
77        if self.buffer_level >= level {
78            self.buffer.push_str(s);
79        }
80        if self.stderr_level >= level {
81            eprint!("{}", s);
82        }
83    }
84
85    #[inline(always)]
86    pub fn level_enabled(&self, level: u32) -> bool {
87        level <= self.effective_level
88    }
89
90    #[inline(always)]
91    pub fn effective_level(&self) -> u32 {
92        self.effective_level
93    }
94
95    #[inline(always)]
96    pub fn buffer_level(&self) -> u32 {
97        self.buffer_level
98    }
99
100    #[inline(always)]
101    pub fn stderr_level(&self) -> u32 {
102        self.stderr_level
103    }
104
105    pub fn set_buffer_level(&mut self, buffer_level: u32) {
106        self.buffer_level = buffer_level;
107        self.effective_level = std::cmp::max(self.effective_level, self.buffer_level);
108    }
109
110    pub fn set_stderr_level(&mut self, stderr_level: u32) {
111        self.stderr_level = stderr_level;
112        self.effective_level = std::cmp::max(self.effective_level, self.stderr_level);
113    }
114
115    pub fn get_buffer(&self) -> &str {
116        &self.buffer
117    }
118
119    pub fn get_and_clear_logs(&mut self) -> String {
120        std::mem::take(&mut self.buffer)
121    }
122
123    pub fn info_logger(&mut self) -> InfoLogger {
124        InfoLogger { logger: self }
125    }
126
127    pub fn warning_logger(&mut self) -> WarningLogger {
128        WarningLogger { logger: self }
129    }
130}
131
132impl Write for InfoLogger<'_> {
133    fn write_str(&mut self, s: &str) -> std::fmt::Result {
134        self.logger.write_info(s);
135        Ok(())
136    }
137}
138
139impl Write for WarningLogger<'_> {
140    fn write_str(&mut self, s: &str) -> std::fmt::Result {
141        self.logger.write_warning(s);
142        Ok(())
143    }
144}