use std::fmt::{Arguments, Display};
use std::path::Path;
use anyhow::Context as _;
pub fn is_stdout(target: &Path) -> bool {
target == Path::new("-")
}
pub struct Report {
stderr: bool,
}
pub fn report(pdf_on_stdout: bool) -> Report {
Report {
stderr: pdf_on_stdout,
}
}
impl Report {
fn line(&self, args: Arguments) {
if self.stderr {
eprintln!("{args}");
} else {
println!("{args}");
}
}
pub fn field<T: Display + ?Sized>(&self, label: &str, value: Option<&T>) {
if let Some(value) = value {
self.line(format_args!("{label:<22} {value}"));
}
}
pub fn field_required(&self, label: &str, value: &dyn Display) {
self.line(format_args!("{label:<22} {value}"));
}
pub fn json<T: serde::Serialize>(&self, value: &T) -> anyhow::Result<()> {
self.line(format_args!("{}", serde_json::to_string_pretty(value)?));
Ok(())
}
}
pub fn field<T: Display + ?Sized>(label: &str, value: Option<&T>) {
report(false).field(label, value);
}
pub fn field_required(label: &str, value: &dyn Display) {
report(false).field_required(label, value);
}
pub fn json<T: serde::Serialize>(value: &T) -> anyhow::Result<()> {
report(false).json(value)
}
pub fn warn_missing_pdf(requested: bool, present: bool) {
if requested && !present {
eprintln!("warning: a PDF was requested but the response contained none");
}
}
pub fn write_pdf(pdf: &[u8], target: &Path) -> anyhow::Result<()> {
use std::io::Write as _;
if is_stdout(target) {
std::io::stdout()
.write_all(pdf)
.context("writing PDF to stdout")?;
} else {
std::fs::write(target, pdf)
.with_context(|| format!("writing PDF to {}", target.display()))?;
eprintln!("PDF written to {}", target.display());
}
Ok(())
}
pub fn read_json_input<T: serde::de::DeserializeOwned>(path: &Path) -> anyhow::Result<T> {
let content = if path == Path::new("-") {
use std::io::Read as _;
let mut buffer = String::new();
std::io::stdin()
.read_to_string(&mut buffer)
.context("reading JSON from stdin")?;
buffer
} else {
std::fs::read_to_string(path)
.with_context(|| format!("reading JSON from {}", path.display()))?
};
serde_json::from_str(&content).with_context(|| {
if path == Path::new("-") {
"parsing JSON from stdin".to_owned()
} else {
format!("parsing JSON from {}", path.display())
}
})
}