pub mod formatting;
mod json;
pub mod monitor;
mod printable;
mod text;
use std::io::Write;
pub use formatting::{
format_bytes, format_duration, format_duration_compact, format_hex, format_ipv4, format_mac,
format_percent, format_rate_bps, format_rate_bytes, format_tc_handle, format_time_ago,
};
pub use json::JsonOutput;
pub use monitor::{
AddressEvent, IpEvent, LinkEvent, MonitorConfig, MonitorEvent, NeighborEvent, RouteEvent,
TcEvent, print_event, print_monitor_start, write_timestamp,
};
pub use text::TextOutput;
#[derive(Debug, Clone, Copy, Default)]
pub struct OutputOptions {
pub stats: bool,
pub details: bool,
pub color: bool,
pub numeric: bool,
pub pretty: bool,
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub enum OutputFormat {
#[default]
Text,
Json,
}
pub trait Printable {
fn print_text<W: Write>(&self, w: &mut W, opts: &OutputOptions) -> std::io::Result<()>;
fn to_json(&self) -> serde_json::Value;
fn print<W: Write>(
&self,
w: &mut W,
format: OutputFormat,
opts: &OutputOptions,
) -> std::io::Result<()> {
match format {
OutputFormat::Text => self.print_text(w, opts),
OutputFormat::Json => {
let json = self.to_json();
if opts.pretty {
serde_json::to_writer_pretty(&mut *w, &json)?;
} else {
serde_json::to_writer(&mut *w, &json)?;
}
writeln!(w)?;
Ok(())
}
}
}
}
pub trait PrintableList {
type Item: Printable;
fn items(&self) -> &[Self::Item];
fn print_text<W: Write>(&self, w: &mut W, opts: &OutputOptions) -> std::io::Result<()> {
for item in self.items() {
item.print_text(w, opts)?;
}
Ok(())
}
fn to_json(&self) -> serde_json::Value {
serde_json::Value::Array(self.items().iter().map(|item| item.to_json()).collect())
}
fn print<W: Write>(
&self,
w: &mut W,
format: OutputFormat,
opts: &OutputOptions,
) -> std::io::Result<()> {
match format {
OutputFormat::Text => self.print_text(w, opts),
OutputFormat::Json => {
let json = self.to_json();
if opts.pretty {
serde_json::to_writer_pretty(&mut *w, &json)?;
} else {
serde_json::to_writer(&mut *w, &json)?;
}
writeln!(w)?;
Ok(())
}
}
}
}
pub fn print_all<T: Printable>(
items: &[T],
format: OutputFormat,
opts: &OutputOptions,
) -> std::io::Result<()> {
let mut stdout = std::io::stdout().lock();
match format {
OutputFormat::Text => {
for item in items {
item.print_text(&mut stdout, opts)?;
}
}
OutputFormat::Json => {
let json: Vec<_> = items.iter().map(|i| i.to_json()).collect();
if opts.pretty {
serde_json::to_writer_pretty(&mut stdout, &json)?;
} else {
serde_json::to_writer(&mut stdout, &json)?;
}
writeln!(stdout)?;
}
}
Ok(())
}
pub fn print_items<T, J, P>(
items: &[T],
format: OutputFormat,
opts: &OutputOptions,
to_json: J,
print_text: P,
) -> std::io::Result<()>
where
J: Fn(&T) -> serde_json::Value,
P: Fn(&mut std::io::StdoutLock<'_>, &T, &OutputOptions) -> std::io::Result<()>,
{
let mut stdout = std::io::stdout().lock();
match format {
OutputFormat::Text => {
for item in items {
print_text(&mut stdout, item, opts)?;
}
}
OutputFormat::Json => {
let json: Vec<_> = items.iter().map(&to_json).collect();
if opts.pretty {
serde_json::to_writer_pretty(&mut stdout, &json)?;
} else {
serde_json::to_writer(&mut stdout, &json)?;
}
writeln!(stdout)?;
}
}
Ok(())
}
pub fn print_items_to<W, T, J, P>(
writer: &mut W,
items: &[T],
format: OutputFormat,
opts: &OutputOptions,
to_json: J,
print_text: P,
) -> std::io::Result<()>
where
W: Write,
J: Fn(&T) -> serde_json::Value,
P: Fn(&mut W, &T, &OutputOptions) -> std::io::Result<()>,
{
match format {
OutputFormat::Text => {
for item in items {
print_text(writer, item, opts)?;
}
}
OutputFormat::Json => {
let json: Vec<_> = items.iter().map(&to_json).collect();
if opts.pretty {
serde_json::to_writer_pretty(&mut *writer, &json)?;
} else {
serde_json::to_writer(&mut *writer, &json)?;
}
writeln!(writer)?;
}
}
Ok(())
}
pub struct OutputBuilder<W: Write> {
writer: W,
indent: usize,
}
impl<W: Write> OutputBuilder<W> {
pub fn new(writer: W) -> Self {
Self { writer, indent: 0 }
}
pub fn indent(&mut self) {
self.indent += 4;
}
pub fn dedent(&mut self) {
self.indent = self.indent.saturating_sub(4);
}
pub fn write_indent(&mut self) -> std::io::Result<()> {
for _ in 0..self.indent {
write!(self.writer, " ")?;
}
Ok(())
}
pub fn writeln(&mut self, s: &str) -> std::io::Result<()> {
self.write_indent()?;
writeln!(self.writer, "{}", s)
}
pub fn write(&mut self, s: &str) -> std::io::Result<()> {
write!(self.writer, "{}", s)
}
pub fn write_kv(&mut self, key: &str, value: &str) -> std::io::Result<()> {
write!(self.writer, "{} {} ", key, value)
}
pub fn newline(&mut self) -> std::io::Result<()> {
writeln!(self.writer)
}
pub fn into_inner(self) -> W {
self.writer
}
}