pcap_processor/output/
formatter.rs1use crate::cli::OutputFormat;
2use crate::error::{PcapError, Result};
3use serde::Serialize;
4
5#[derive(Serialize)]
6pub struct OutputData {
7 pub field: String,
8 pub total_unique: usize,
9 pub values: Vec<ValueEntry>,
10}
11
12#[derive(Serialize)]
13pub struct ValueEntry {
14 pub value: String,
15 pub count: usize,
16}
17
18pub fn format_output(data: &OutputData, format: OutputFormat, show_count: bool) -> Result<String> {
19 match format {
20 OutputFormat::Plain => format_plain(data, show_count),
21 OutputFormat::Json => format_json(data, show_count),
22 OutputFormat::Csv => format_csv(data, show_count),
23 }
24}
25
26fn format_plain(data: &OutputData, show_count: bool) -> Result<String> {
27 let mut output = String::new();
28
29 for entry in &data.values {
30 if show_count {
31 output.push_str(&format!("{}\t{}\n", entry.count, entry.value));
32 } else {
33 output.push_str(&entry.value);
34 output.push('\n');
35 }
36 }
37
38 Ok(output)
39}
40
41fn format_json(data: &OutputData, show_count: bool) -> Result<String> {
42 #[derive(Serialize)]
43 struct JsonOutput<'a> {
44 field: &'a str,
45 total_unique: usize,
46 values: Vec<JsonValue<'a>>,
47 }
48
49 #[derive(Serialize)]
50 struct JsonValue<'a> {
51 value: &'a str,
52 #[serde(skip_serializing_if = "Option::is_none")]
53 count: Option<usize>,
54 }
55
56 let output = JsonOutput {
57 field: &data.field,
58 total_unique: data.total_unique,
59 values: data
60 .values
61 .iter()
62 .map(|e| JsonValue {
63 value: &e.value,
64 count: if show_count { Some(e.count) } else { None },
65 })
66 .collect(),
67 };
68
69 serde_json::to_string_pretty(&output).map_err(|e| PcapError::OutputFormat(e.to_string()))
70}
71
72fn format_csv(data: &OutputData, show_count: bool) -> Result<String> {
73 let mut wtr = csv::Writer::from_writer(Vec::new());
74
75 if show_count {
77 wtr.write_record(["value", "count"])
78 .map_err(|e| PcapError::OutputFormat(e.to_string()))?;
79 } else {
80 wtr.write_record(["value"])
81 .map_err(|e| PcapError::OutputFormat(e.to_string()))?;
82 }
83
84 for entry in &data.values {
86 if show_count {
87 wtr.write_record([&entry.value, &entry.count.to_string()])
88 .map_err(|e| PcapError::OutputFormat(e.to_string()))?;
89 } else {
90 wtr.write_record([&entry.value])
91 .map_err(|e| PcapError::OutputFormat(e.to_string()))?;
92 }
93 }
94
95 let bytes = wtr
96 .into_inner()
97 .map_err(|e| PcapError::OutputFormat(e.to_string()))?;
98
99 String::from_utf8(bytes).map_err(|e| PcapError::OutputFormat(e.to_string()))
100}