Skip to main content

pan_common/
output.rs

1use crate::error::StructuredError;
2use serde::Serialize;
3
4/// Output format for CLI tools.
5#[derive(Debug, Clone, Copy, PartialEq, Eq)]
6#[cfg_attr(feature = "clap", derive(clap::ValueEnum))]
7pub enum OutputFormat {
8    Human,
9    Json,
10}
11
12/// Print a value as either human text or JSON.
13pub fn print_output<T: Serialize>(format: OutputFormat, human_text: &str, value: &T) {
14    match format {
15        OutputFormat::Human => println!("{human_text}"),
16        OutputFormat::Json => {
17            println!(
18                "{}",
19                serde_json::to_string_pretty(value).unwrap_or_else(|_| "{}".into())
20            );
21        }
22    }
23}
24
25/// Print a JSON value directly.
26pub fn print_json(value: &serde_json::Value) {
27    // Value serialization is infallible — unwrap is safe here.
28    println!("{}", serde_json::to_string_pretty(value).unwrap());
29}
30
31/// Print an error in the appropriate format and return the exit code.
32pub fn print_error<E: StructuredError>(format: OutputFormat, err: &E) -> i32 {
33    let exit_code: u8 = err.exit_code().into();
34    match format {
35        OutputFormat::Human => {
36            eprintln!("error: {err}");
37            let suggestion = err.suggestion();
38            if !suggestion.is_empty() {
39                eprintln!("  hint: {suggestion}");
40            }
41        }
42        OutputFormat::Json => {
43            let json = serde_json::to_string_pretty(err).unwrap_or_else(|_| {
44                serde_json::to_string(&serde_json::json!({
45                    "error": "serialization_failed",
46                    "message": err.to_string()
47                }))
48                .unwrap_or_default()
49            });
50            eprintln!("{json}");
51        }
52    }
53    exit_code as i32
54}