1use std::io;
2use std::io::Write;
3use std::sync::Arc;
4use std::sync::Mutex;
5use std::sync::PoisonError;
6
7#[derive(strum::Display, strum::EnumString, strum::VariantNames)]
9#[strum(serialize_all = "kebab-case")]
10#[derive(Default)]
11pub enum ReportingTarget {
12 #[strum(serialize = "stdout", serialize = "out")]
14 #[default]
15 Stdout,
16 #[strum(serialize = "stderr", serialize = "err")]
18 Stderr,
19 #[strum(disabled)]
21 Writer(Arc<Mutex<Box<dyn Write + Send>>>),
22}
23
24impl Clone for ReportingTarget {
25 fn clone(&self) -> Self {
26 match self {
27 ReportingTarget::Stdout => ReportingTarget::Stdout,
28 ReportingTarget::Stderr => ReportingTarget::Stderr,
29 ReportingTarget::Writer(writer) => ReportingTarget::Writer(Arc::clone(writer)),
30 }
31 }
32}
33
34impl std::fmt::Debug for ReportingTarget {
35 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
36 match self {
37 ReportingTarget::Stdout => write!(f, "ReportingTarget::Stdout"),
38 ReportingTarget::Stderr => write!(f, "ReportingTarget::Stderr"),
39 ReportingTarget::Writer(_) => write!(f, "ReportingTarget::Writer(..)"),
40 }
41 }
42}
43
44impl ReportingTarget {
45 #[must_use]
53 pub fn buffer() -> (Self, Arc<Mutex<Vec<u8>>>) {
54 let buffer = Arc::new(Mutex::new(Vec::new()));
55 let writer_buffer = Arc::clone(&buffer);
56 let target = ReportingTarget::Writer(Arc::new(Mutex::new(Box::new(BufferWriter { buffer: writer_buffer }))));
57 (target, buffer)
58 }
59
60 pub(crate) fn resolve(&self) -> Box<dyn Write + '_> {
66 match self {
67 ReportingTarget::Stdout => Box::new(io::stdout()),
68 ReportingTarget::Stderr => Box::new(io::stderr()),
69 ReportingTarget::Writer(writer) => Box::new(LockedWriter { writer: Arc::clone(writer) }),
70 }
71 }
72}
73
74struct LockedWriter {
76 writer: Arc<Mutex<Box<dyn Write + Send>>>,
77}
78
79impl Write for LockedWriter {
80 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
81 self.writer.lock().unwrap_or_else(PoisonError::into_inner).write(buf)
82 }
83
84 fn flush(&mut self) -> io::Result<()> {
85 self.writer.lock().unwrap_or_else(PoisonError::into_inner).flush()
86 }
87}
88
89struct BufferWriter {
91 buffer: Arc<Mutex<Vec<u8>>>,
92}
93
94impl Write for BufferWriter {
95 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
96 self.buffer.lock().unwrap_or_else(PoisonError::into_inner).write(buf)
97 }
98
99 fn flush(&mut self) -> io::Result<()> {
100 self.buffer.lock().unwrap_or_else(PoisonError::into_inner).flush()
101 }
102}