Skip to main content

cai_output/
lib.rs

1//! CAI Output - Output formatters
2//!
3//! Trait-based output formatting for AI coding interaction data.
4
5#![warn(missing_docs)]
6
7pub mod formats;
8pub mod formatter;
9
10pub use formatter::{Formatter, FormatterConfig};
11
12/// Re-export formatters
13pub use formats::{
14    AiFormatter, CsvFormatter, JsonFormatter, JsonlFormatter, StatsFormatter, TableFormatter,
15};
16
17/// Output format options
18#[derive(Debug, Clone, Copy, PartialEq, Eq)]
19#[non_exhaustive]
20pub enum OutputFormat {
21    /// Standard JSON array
22    Json,
23    /// JSON Lines (newline-delimited JSON)
24    Jsonl,
25    /// CSV with headers
26    Csv,
27    /// Pretty terminal table
28    Table,
29    /// AI-optimized compact format
30    Ai,
31    /// Summary statistics
32    Stats,
33}
34
35/// Dynamic formatter that can hold any formatter type
36#[non_exhaustive]
37pub enum DynFormatter {
38    /// JSON array formatter
39    Json(JsonFormatter),
40    /// JSON Lines formatter
41    Jsonl(JsonlFormatter),
42    /// CSV formatter
43    Csv(CsvFormatter),
44    /// Table formatter
45    Table(TableFormatter),
46    /// AI-optimized formatter
47    Ai(AiFormatter),
48    /// Statistics formatter
49    Stats(StatsFormatter),
50}
51
52impl DynFormatter {
53    /// Create formatter from output format
54    pub fn from_format(format: OutputFormat) -> Self {
55        match format {
56            OutputFormat::Json => Self::Json(JsonFormatter::default()),
57            OutputFormat::Jsonl => Self::Jsonl(JsonlFormatter::default()),
58            OutputFormat::Csv => Self::Csv(CsvFormatter::default()),
59            OutputFormat::Table => Self::Table(TableFormatter::default()),
60            OutputFormat::Ai => Self::Ai(AiFormatter::default()),
61            OutputFormat::Stats => Self::Stats(StatsFormatter::default()),
62        }
63    }
64
65    /// Get the config for this formatter
66    pub fn config(&self) -> &FormatterConfig {
67        match self {
68            Self::Json(f) => f.config(),
69            Self::Jsonl(f) => f.config(),
70            Self::Csv(f) => f.config(),
71            Self::Table(f) => f.config(),
72            Self::Ai(f) => f.config(),
73            Self::Stats(f) => f.config(),
74        }
75    }
76
77    /// Set config for this formatter
78    pub fn set_config(&mut self, config: FormatterConfig) {
79        match self {
80            Self::Json(f) => f.set_config(config),
81            Self::Jsonl(f) => f.set_config(config),
82            Self::Csv(f) => f.set_config(config),
83            Self::Table(f) => f.set_config(config),
84            Self::Ai(f) => f.set_config(config),
85            Self::Stats(f) => f.set_config(config),
86        }
87    }
88}
89
90// Delegate Formatter trait methods
91macro_rules! delegate_formatter {
92    ($($format:ident),*) => {
93        impl Formatter for DynFormatter {
94            fn format<W: std::io::Write>(&self, entries: &[cai_core::Entry], writer: &mut W) -> cai_core::Result<()> {
95                match self {
96                    $(Self::$format(f) => f.format(entries, writer),)*
97                }
98            }
99
100            fn format_one<W: std::io::Write>(&self, entry: &cai_core::Entry, writer: &mut W) -> cai_core::Result<()> {
101                match self {
102                    $(Self::$format(f) => f.format_one(entry, writer),)*
103                }
104            }
105
106            fn config(&self) -> &FormatterConfig {
107                match self {
108                    $(Self::$format(f) => f.config(),)*
109                }
110            }
111
112            fn set_config(&mut self, config: FormatterConfig) {
113                match self {
114                    $(Self::$format(f) => f.set_config(config),)*
115                }
116            }
117        }
118    }
119}
120
121delegate_formatter!(Json, Jsonl, Csv, Table, Ai, Stats);