ralph_workflow/json_parser/printer/
traits.rs1pub trait Printable: std::io::Write {
11 fn is_terminal(&self) -> bool;
16}
17
18#[derive(Debug, Clone)]
20pub struct StdoutPrinter {
21 buffer: String,
22 is_terminal: bool,
23}
24
25impl StdoutPrinter {
26 #[must_use]
28 pub fn new() -> Self {
29 Self {
30 buffer: String::new(),
31 is_terminal: std::io::stdout().is_terminal(),
32 }
33 }
34
35 #[must_use]
37 pub fn write_text(self, text: &str) -> Self {
38 Self {
39 buffer: format!("{}{}", self.buffer, text),
40 is_terminal: self.is_terminal,
41 }
42 }
43
44 #[must_use]
46 pub fn write_line(self, line: &str) -> Self {
47 self.write_text(&format!("{}\n", line))
48 }
49
50 #[must_use]
53 pub fn emit(self) -> (Self, String) {
54 let output = self.buffer.clone();
55 (
56 Self {
57 buffer: String::new(),
58 is_terminal: self.is_terminal,
59 },
60 output,
61 )
62 }
63
64 #[must_use]
66 pub fn get_buffer(&self) -> &str {
67 &self.buffer
68 }
69
70 pub fn flush(self) -> Self {
72 self
73 }
74}
75
76impl Default for StdoutPrinter {
77 fn default() -> Self {
78 Self::new()
79 }
80}
81
82impl Printable for StdoutPrinter {
83 fn is_terminal(&self) -> bool {
84 self.is_terminal
85 }
86}
87
88impl std::io::Write for StdoutPrinter {
89 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
90 let s =
91 std::str::from_utf8(buf).map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
92 self.buffer.push_str(s);
93 std::io::stdout().write(buf)
94 }
95
96 fn flush(&mut self) -> io::Result<()> {
97 std::io::stdout().flush()
98 }
99}
100
101#[derive(Debug, Clone)]
103#[cfg(any(test, feature = "test-utils"))]
104pub struct StderrPrinter {
105 buffer: String,
106 is_terminal: bool,
107}
108
109#[cfg(any(test, feature = "test-utils"))]
110impl StderrPrinter {
111 #[must_use]
113 pub fn new() -> Self {
114 Self {
115 buffer: String::new(),
116 is_terminal: std::io::stderr().is_terminal(),
117 }
118 }
119
120 #[must_use]
122 pub fn write_text(self, text: &str) -> Self {
123 Self {
124 buffer: format!("{}{}", self.buffer, text),
125 is_terminal: self.is_terminal,
126 }
127 }
128
129 #[must_use]
131 pub fn write_line(self, line: &str) -> Self {
132 self.write_text(&format!("{}\n", line))
133 }
134
135 #[must_use]
138 pub fn emit(self) -> (Self, String) {
139 let output = self.buffer.clone();
140 (
141 Self {
142 buffer: String::new(),
143 is_terminal: self.is_terminal,
144 },
145 output,
146 )
147 }
148
149 #[must_use]
151 pub fn get_buffer(&self) -> &str {
152 &self.buffer
153 }
154
155 pub fn flush(self) -> Self {
157 self
158 }
159}
160
161#[cfg(any(test, feature = "test-utils"))]
162impl Default for StderrPrinter {
163 fn default() -> Self {
164 Self::new()
165 }
166}
167
168#[cfg(any(test, feature = "test-utils"))]
169impl std::io::Write for StderrPrinter {
170 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
171 let s =
172 std::str::from_utf8(buf).map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
173 self.buffer.push_str(s);
174 std::io::stderr().write(buf)
175 }
176
177 fn flush(&mut self) -> io::Result<()> {
178 std::io::stderr().flush()
179 }
180}
181
182#[cfg(any(test, feature = "test-utils"))]
183impl Printable for StderrPrinter {
184 fn is_terminal(&self) -> bool {
185 self.is_terminal
186 }
187}
188
189pub type SharedPrinter = Rc<RefCell<dyn Printable>>;
194
195#[must_use]
197pub fn shared_stdout() -> SharedPrinter {
198 Rc::new(RefCell::new(StdoutPrinter::new()))
199}