1use std::{
14 fmt,
15 io::{IsTerminal, Stdout, Write, stdout},
16};
17
18use anyhow::{Context, Result};
19use serde::Serialize;
20
21use crate::{clap::args::JsonFlag, output::Bytes};
22
23pub trait PrintTable {
25 fn print(&self, writer: &mut dyn Write, table_max_width: Option<u16>) -> Result<()>;
28}
29
30pub trait Printer {
32 fn out<T: fmt::Display + Serialize>(&mut self, data: T) -> Result<()>;
34
35 fn event<T: fmt::Display + Serialize>(&mut self, event: T) -> Result<()>;
41
42 fn out_bytes(&mut self, bytes: Bytes) -> Result<()>;
45
46 fn is_json(&self) -> bool {
48 false
49 }
50}
51
52pub struct StdoutPrinter {
54 stdout: Stdout,
55 json: bool,
56}
57
58impl StdoutPrinter {
59 pub fn new(json: &JsonFlag) -> Self {
61 Self {
62 stdout: stdout(),
63 json: json.enabled,
64 }
65 }
66
67 fn write_json_line<T: Serialize>(&mut self, data: &T) -> Result<()> {
68 serde_json::to_writer(&mut self.stdout, data).context("Print JSON to stdout error")?;
69 writeln!(self.stdout)?;
70 self.stdout.flush()?;
71 Ok(())
72 }
73}
74
75impl Printer for StdoutPrinter {
76 fn out<T: fmt::Display + Serialize>(&mut self, data: T) -> Result<()> {
77 if !self.json {
78 write!(self.stdout, "{data}")?;
79 return Ok(());
80 }
81
82 if self.stdout.is_terminal() {
83 serde_json::to_writer_pretty(&mut self.stdout, &data)
84 .context("Print pretty JSON to stdout error")?;
85 writeln!(self.stdout)?;
86 return Ok(());
87 }
88
89 self.write_json_line(&data)
93 }
94
95 fn event<T: fmt::Display + Serialize>(&mut self, event: T) -> Result<()> {
96 if self.json {
99 return self.write_json_line(&event);
100 }
101
102 if self.stdout.is_terminal() {
105 write!(self.stdout, "{event}")?;
106 self.stdout.flush()?;
107 }
108
109 Ok(())
110 }
111
112 fn out_bytes(&mut self, bytes: Bytes) -> Result<()> {
113 if self.json {
114 return self.out(bytes);
115 }
116
117 self.stdout
118 .write_all(&bytes.data)
119 .context("Write bytes to stdout error")?;
120 self.stdout.flush().context("Flush stdout error")?;
121
122 Ok(())
123 }
124
125 fn is_json(&self) -> bool {
126 self.json
127 }
128}
129
130#[cfg(test)]
132#[derive(Default)]
133pub struct TestPrinter {
134 pub output: String,
136 pub events: Vec<String>,
138}
139
140#[cfg(test)]
141impl Printer for TestPrinter {
142 fn out<T: fmt::Display + Serialize>(&mut self, data: T) -> Result<()> {
143 self.output = data.to_string();
144 Ok(())
145 }
146
147 fn event<T: fmt::Display + Serialize>(&mut self, event: T) -> Result<()> {
148 self.events.push(event.to_string());
149 Ok(())
150 }
151
152 fn out_bytes(&mut self, bytes: Bytes) -> Result<()> {
153 self.output = String::from_utf8_lossy(&bytes.data).into_owned();
154 Ok(())
155 }
156}