1 use std::io::{self, Write};
2 use std::sync::Mutex;
3 
4 use termcolor::{self, ColorSpec, WriteColor};
5 
6 use crate::fmt::{WritableTarget, WriteStyle};
7 
8 pub(in crate::fmt::writer) struct BufferWriter {
9     inner: termcolor::BufferWriter,
10     uncolored_target: Option<WritableTarget>,
11     write_style: WriteStyle,
12 }
13 
14 impl BufferWriter {
stderr(is_test: bool, write_style: WriteStyle) -> Self15     pub(in crate::fmt::writer) fn stderr(is_test: bool, write_style: WriteStyle) -> Self {
16         BufferWriter {
17             inner: termcolor::BufferWriter::stderr(write_style.into_color_choice()),
18             uncolored_target: if is_test {
19                 Some(WritableTarget::PrintStderr)
20             } else {
21                 None
22             },
23             write_style,
24         }
25     }
26 
stdout(is_test: bool, write_style: WriteStyle) -> Self27     pub(in crate::fmt::writer) fn stdout(is_test: bool, write_style: WriteStyle) -> Self {
28         BufferWriter {
29             inner: termcolor::BufferWriter::stdout(write_style.into_color_choice()),
30             uncolored_target: if is_test {
31                 Some(WritableTarget::PrintStdout)
32             } else {
33                 None
34             },
35             write_style,
36         }
37     }
38 
pipe(pipe: Box<Mutex<dyn io::Write + Send + 'static>>) -> Self39     pub(in crate::fmt::writer) fn pipe(pipe: Box<Mutex<dyn io::Write + Send + 'static>>) -> Self {
40         let write_style = WriteStyle::Never;
41         BufferWriter {
42             // The inner Buffer is never printed from, but it is still needed to handle coloring and other formatting
43             inner: termcolor::BufferWriter::stderr(write_style.into_color_choice()),
44             uncolored_target: Some(WritableTarget::Pipe(pipe)),
45             write_style,
46         }
47     }
48 
write_style(&self) -> WriteStyle49     pub(in crate::fmt::writer) fn write_style(&self) -> WriteStyle {
50         self.write_style
51     }
52 
buffer(&self) -> Buffer53     pub(in crate::fmt::writer) fn buffer(&self) -> Buffer {
54         Buffer {
55             inner: self.inner.buffer(),
56             has_uncolored_target: self.uncolored_target.is_some(),
57         }
58     }
59 
print(&self, buf: &Buffer) -> io::Result<()>60     pub(in crate::fmt::writer) fn print(&self, buf: &Buffer) -> io::Result<()> {
61         if let Some(target) = &self.uncolored_target {
62             target.print(buf)
63         } else {
64             self.inner.print(&buf.inner)
65         }
66     }
67 }
68 
69 pub(in crate::fmt) struct Buffer {
70     inner: termcolor::Buffer,
71     has_uncolored_target: bool,
72 }
73 
74 impl Buffer {
clear(&mut self)75     pub(in crate::fmt) fn clear(&mut self) {
76         self.inner.clear()
77     }
78 
write(&mut self, buf: &[u8]) -> io::Result<usize>79     pub(in crate::fmt) fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
80         self.inner.write(buf)
81     }
82 
flush(&mut self) -> io::Result<()>83     pub(in crate::fmt) fn flush(&mut self) -> io::Result<()> {
84         self.inner.flush()
85     }
86 
as_bytes(&self) -> &[u8]87     pub(in crate::fmt) fn as_bytes(&self) -> &[u8] {
88         self.inner.as_slice()
89     }
90 
set_color(&mut self, spec: &ColorSpec) -> io::Result<()>91     pub(in crate::fmt) fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> {
92         // Ignore styles for test captured logs because they can't be printed
93         if !self.has_uncolored_target {
94             self.inner.set_color(spec)
95         } else {
96             Ok(())
97         }
98     }
99 
reset(&mut self) -> io::Result<()>100     pub(in crate::fmt) fn reset(&mut self) -> io::Result<()> {
101         // Ignore styles for test captured logs because they can't be printed
102         if !self.has_uncolored_target {
103             self.inner.reset()
104         } else {
105             Ok(())
106         }
107     }
108 }
109