use chrono::{DateTime, Local};
#[derive(Clone, Copy, Eq, PartialEq)]
pub enum OutputFormat {
Csv,
Human(NoiseLevel),
Json,
JsonCompact,
Silent,
TerseText,
Tsv,
}
#[derive(Clone, Copy, Eq, PartialEq)]
pub enum NoiseLevel {
Verbose,
Normal,
Quiet,
}
impl OutputFormat {
pub fn format_time(&self, dt: DateTime<Local>) -> String {
dt.to_rfc2822()
}
pub fn is_nonquiet_for_humans(&self) -> bool {
match self {
OutputFormat::Human(NoiseLevel::Quiet) => false,
OutputFormat::Human(_) => true,
_ => false,
}
}
pub fn log_always(&self, labels: Vec<&str>, values: Vec<Vec<&str>>) {
if let OutputFormat::TerseText = self {
quiet_print(values);
} else {
self.log(labels, values);
}
}
pub fn log(&self, labels: Vec<&str>, values: Vec<Vec<&str>>) {
if let OutputFormat::Silent = self {
return;
}
if let OutputFormat::TerseText = self {
return;
}
match &self {
OutputFormat::Csv => {
let print_csv = join_and_print(",");
print_csv(labels);
values.into_iter().for_each(print_csv)
}
OutputFormat::Human(noise) => match noise {
NoiseLevel::Verbose => {
values.into_iter().for_each(|line| match line.len() {
0 => (),
1 => println!("{}", line.first().unwrap()),
2 => println!("{}: {}", line.first().unwrap(), line.get(1).unwrap()),
_ => println!(
"{}: {} ({})",
line.first().unwrap(),
line.get(1).unwrap(),
line.iter()
.skip(2)
.map(|s| s.to_string())
.collect::<Vec<_>>()
.join(", ")
),
});
}
NoiseLevel::Normal => {
values.into_iter().for_each(|line| {
if let (Some(label), Some(item)) = (line.first(), line.get(1)) {
println!("{}: {}", label, item);
} else if let Some(info) = line.first() {
println!("{}", info);
}
});
}
NoiseLevel::Quiet => quiet_print(values),
},
OutputFormat::Json => {
let keys = labels;
let objs = values
.into_iter()
.map(|vals| {
let mut obj = json::JsonValue::new_object();
keys.iter().zip(vals).for_each(|(k, v)| obj[*k] = v.into());
obj
})
.collect::<Vec<_>>();
println!("{}", json::stringify_pretty(objs, 2));
}
OutputFormat::JsonCompact => {
let keys = labels;
let objs = values
.into_iter()
.map(|vals| {
let mut obj = json::JsonValue::new_object();
keys.iter().zip(vals).for_each(|(k, v)| obj[*k] = v.into());
obj
})
.collect::<Vec<_>>();
println!("{}", json::stringify(objs));
}
OutputFormat::Silent => {
unreachable!("[BUG] Sigi should always exit outputting before this point.")
}
OutputFormat::TerseText => {
unreachable!("[BUG] Sigi should always exit outputting before this point.")
}
OutputFormat::Tsv => {
let print_tsv = join_and_print("\t");
print_tsv(labels);
values.into_iter().for_each(print_tsv)
}
}
}
}
fn quiet_print(values: Vec<Vec<&str>>) {
values.into_iter().for_each(|line| {
if let Some(message) = line.get(1) {
println!("{}", message);
} else if let Some(message) = line.first() {
println!("{}", message);
}
})
}
fn join_and_print(sep: &str) -> impl Fn(Vec<&str>) {
let sep = sep.to_string();
move |tokens: Vec<&str>| println!("{}", tokens.join(&sep))
}