env_logger/fmt/writer/
mod.rs1mod atty;
2mod termcolor;
3
4use self::atty::{is_stderr, is_stdout};
5use self::termcolor::BufferWriter;
6use std::{fmt, io};
7
8pub(in crate::fmt) mod glob {
9 pub use super::termcolor::glob::*;
10 pub use super::*;
11}
12
13pub(in crate::fmt) use self::termcolor::Buffer;
14
15#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
17pub enum Target {
18 Stdout,
20 Stderr,
22}
23
24impl Default for Target {
25 fn default() -> Self {
26 Target::Stderr
27 }
28}
29
30#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
32pub enum WriteStyle {
33 Auto,
35 Always,
37 Never,
39}
40
41impl Default for WriteStyle {
42 fn default() -> Self {
43 WriteStyle::Auto
44 }
45}
46
47pub(crate) struct Writer {
49 inner: BufferWriter,
50 write_style: WriteStyle,
51}
52
53impl Writer {
54 pub fn write_style(&self) -> WriteStyle {
55 self.write_style
56 }
57
58 pub(in crate::fmt) fn buffer(&self) -> Buffer {
59 self.inner.buffer()
60 }
61
62 pub(in crate::fmt) fn print(&self, buf: &Buffer) -> io::Result<()> {
63 self.inner.print(buf)
64 }
65}
66
67pub(crate) struct Builder {
71 target: Target,
72 write_style: WriteStyle,
73 is_test: bool,
74 built: bool,
75}
76
77impl Builder {
78 pub(crate) fn new() -> Self {
80 Builder {
81 target: Default::default(),
82 write_style: Default::default(),
83 is_test: false,
84 built: false,
85 }
86 }
87
88 pub(crate) fn target(&mut self, target: Target) -> &mut Self {
90 self.target = target;
91 self
92 }
93
94 pub(crate) fn parse_write_style(&mut self, write_style: &str) -> &mut Self {
100 self.write_style(parse_write_style(write_style))
101 }
102
103 pub(crate) fn write_style(&mut self, write_style: WriteStyle) -> &mut Self {
105 self.write_style = write_style;
106 self
107 }
108
109 pub(crate) fn is_test(&mut self, is_test: bool) -> &mut Self {
111 self.is_test = is_test;
112 self
113 }
114
115 pub(crate) fn build(&mut self) -> Writer {
117 assert!(!self.built, "attempt to re-use consumed builder");
118 self.built = true;
119
120 let color_choice = match self.write_style {
121 WriteStyle::Auto => {
122 if match self.target {
123 Target::Stderr => is_stderr(),
124 Target::Stdout => is_stdout(),
125 } {
126 WriteStyle::Auto
127 } else {
128 WriteStyle::Never
129 }
130 }
131 color_choice => color_choice,
132 };
133
134 let writer = match self.target {
135 Target::Stderr => BufferWriter::stderr(self.is_test, color_choice),
136 Target::Stdout => BufferWriter::stdout(self.is_test, color_choice),
137 };
138
139 Writer {
140 inner: writer,
141 write_style: self.write_style,
142 }
143 }
144}
145
146impl Default for Builder {
147 fn default() -> Self {
148 Builder::new()
149 }
150}
151
152impl fmt::Debug for Builder {
153 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
154 f.debug_struct("Logger")
155 .field("target", &self.target)
156 .field("write_style", &self.write_style)
157 .finish()
158 }
159}
160
161impl fmt::Debug for Writer {
162 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
163 f.debug_struct("Writer").finish()
164 }
165}
166
167fn parse_write_style(spec: &str) -> WriteStyle {
168 match spec {
169 "auto" => WriteStyle::Auto,
170 "always" => WriteStyle::Always,
171 "never" => WriteStyle::Never,
172 _ => Default::default(),
173 }
174}
175
176#[cfg(test)]
177mod tests {
178 use super::*;
179
180 #[test]
181 fn parse_write_style_valid() {
182 let inputs = vec![
183 ("auto", WriteStyle::Auto),
184 ("always", WriteStyle::Always),
185 ("never", WriteStyle::Never),
186 ];
187
188 for (input, expected) in inputs {
189 assert_eq!(expected, parse_write_style(input));
190 }
191 }
192
193 #[test]
194 fn parse_write_style_invalid() {
195 let inputs = vec!["", "true", "false", "NEVER!!"];
196
197 for input in inputs {
198 assert_eq!(WriteStyle::Auto, parse_write_style(input));
199 }
200 }
201}