env_logger/fmt/writer/
buffer.rs1use std::{io, sync::Mutex};
2
3use crate::fmt::writer::WriteStyle;
4
5#[derive(Debug)]
6pub(in crate::fmt::writer) struct BufferWriter {
7 target: WritableTarget,
8 write_style: WriteStyle,
9}
10
11impl BufferWriter {
12 pub(in crate::fmt::writer) fn stderr(is_test: bool, write_style: WriteStyle) -> Self {
13 BufferWriter {
14 target: if is_test {
15 WritableTarget::PrintStderr
16 } else {
17 WritableTarget::WriteStderr
18 },
19 write_style,
20 }
21 }
22
23 pub(in crate::fmt::writer) fn stdout(is_test: bool, write_style: WriteStyle) -> Self {
24 BufferWriter {
25 target: if is_test {
26 WritableTarget::PrintStdout
27 } else {
28 WritableTarget::WriteStdout
29 },
30 write_style,
31 }
32 }
33
34 pub(in crate::fmt::writer) fn pipe(
35 pipe: Box<Mutex<dyn io::Write + Send + 'static>>,
36 write_style: WriteStyle,
37 ) -> Self {
38 BufferWriter {
39 target: WritableTarget::Pipe(pipe),
40 write_style,
41 }
42 }
43
44 pub(in crate::fmt::writer) fn write_style(&self) -> WriteStyle {
45 self.write_style
46 }
47
48 pub(in crate::fmt::writer) fn buffer(&self) -> Buffer {
49 Buffer(Vec::new())
50 }
51
52 pub(in crate::fmt::writer) fn print(&self, buf: &Buffer) -> io::Result<()> {
53 #![allow(clippy::print_stdout)] #![allow(clippy::print_stderr)] use std::io::Write as _;
57
58 let buf = buf.as_bytes();
59 match &self.target {
60 WritableTarget::WriteStdout => {
61 let stream = io::stdout();
62 #[cfg(feature = "color")]
63 let stream = anstream::AutoStream::new(stream, self.write_style.into());
64 let mut stream = stream.lock();
65 stream.write_all(buf)?;
66 stream.flush()?;
67 }
68 WritableTarget::PrintStdout => {
69 #[cfg(feature = "color")]
70 let buf = adapt(buf, self.write_style)?;
71 #[cfg(feature = "color")]
72 let buf = &buf;
73 let buf = String::from_utf8_lossy(buf);
74 print!("{buf}");
75 }
76 WritableTarget::WriteStderr => {
77 let stream = io::stderr();
78 #[cfg(feature = "color")]
79 let stream = anstream::AutoStream::new(stream, self.write_style.into());
80 let mut stream = stream.lock();
81 stream.write_all(buf)?;
82 stream.flush()?;
83 }
84 WritableTarget::PrintStderr => {
85 #[cfg(feature = "color")]
86 let buf = adapt(buf, self.write_style)?;
87 #[cfg(feature = "color")]
88 let buf = &buf;
89 let buf = String::from_utf8_lossy(buf);
90 eprint!("{buf}");
91 }
92 WritableTarget::Pipe(pipe) => {
93 #[cfg(feature = "color")]
94 let buf = adapt(buf, self.write_style)?;
95 #[cfg(feature = "color")]
96 let buf = &buf;
97 let mut stream = pipe.lock().expect("no panics while held");
98 stream.write_all(buf)?;
99 stream.flush()?;
100 }
101 }
102
103 Ok(())
104 }
105}
106
107#[cfg(feature = "color")]
108fn adapt(buf: &[u8], write_style: WriteStyle) -> io::Result<Vec<u8>> {
109 use std::io::Write as _;
110
111 let adapted = Vec::with_capacity(buf.len());
112 let mut stream = anstream::AutoStream::new(adapted, write_style.into());
113 stream.write_all(buf)?;
114 let adapted = stream.into_inner();
115 Ok(adapted)
116}
117
118pub(in crate::fmt) struct Buffer(Vec<u8>);
119
120impl Buffer {
121 pub(in crate::fmt) fn clear(&mut self) {
122 self.0.clear();
123 }
124
125 pub(in crate::fmt) fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
126 self.0.extend(buf);
127 Ok(buf.len())
128 }
129
130 pub(in crate::fmt) fn flush(&mut self) -> io::Result<()> {
131 Ok(())
132 }
133
134 pub(in crate::fmt) fn as_bytes(&self) -> &[u8] {
135 &self.0
136 }
137}
138
139impl std::fmt::Debug for Buffer {
140 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
141 String::from_utf8_lossy(self.as_bytes()).fmt(f)
142 }
143}
144
145pub(super) enum WritableTarget {
149 WriteStdout,
151 PrintStdout,
153 WriteStderr,
155 PrintStderr,
157 Pipe(Box<Mutex<dyn io::Write + Send + 'static>>),
159}
160
161impl std::fmt::Debug for WritableTarget {
162 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
163 write!(
164 f,
165 "{}",
166 match self {
167 Self::WriteStdout => "stdout",
168 Self::PrintStdout => "stdout",
169 Self::WriteStderr => "stderr",
170 Self::PrintStderr => "stderr",
171 Self::Pipe(_) => "pipe",
172 }
173 )
174 }
175}