copybook_codec/lib_api/
run_summary.rs1use std::fmt;
5
6#[derive(Debug, Default, Clone, PartialEq)]
11pub struct RunSummary {
12 pub records_processed: u64,
14 pub records_with_errors: u64,
16 pub warnings: u64,
18 pub processing_time_ms: u64,
20 pub bytes_processed: u64,
25 pub schema_fingerprint: String,
27 pub throughput_mbps: f64,
29 pub peak_memory_bytes: Option<u64>,
31 pub threads_used: usize,
33}
34
35impl RunSummary {
36 #[must_use]
38 pub fn new() -> Self {
39 Self::default()
40 }
41
42 #[must_use]
44 pub fn with_threads(threads: usize) -> Self {
45 Self {
46 threads_used: threads,
47 ..Self::default()
48 }
49 }
50
51 #[allow(clippy::cast_precision_loss)]
53 pub fn calculate_throughput(&mut self) {
54 if self.processing_time_ms > 0 {
55 let seconds = self.processing_time_ms as f64 / 1000.0;
56 let megabytes = self.bytes_processed as f64 / (1024.0 * 1024.0);
57 self.throughput_mbps = megabytes / seconds;
58 }
59 }
60
61 #[must_use]
63 pub const fn has_errors(&self) -> bool {
64 self.records_with_errors > 0
65 }
66
67 #[must_use]
69 pub const fn has_warnings(&self) -> bool {
70 self.warnings > 0
71 }
72
73 #[must_use]
75 pub const fn is_successful(&self) -> bool {
76 !self.has_errors()
77 }
78
79 #[must_use]
81 pub const fn total_records(&self) -> u64 {
82 self.records_processed + self.records_with_errors
83 }
84
85 #[must_use]
87 #[allow(clippy::cast_precision_loss)]
88 pub fn success_rate(&self) -> f64 {
89 let total = self.total_records();
90 if total == 0 {
91 100.0
92 } else {
93 (self.records_processed as f64 / total as f64) * 100.0
94 }
95 }
96
97 #[must_use]
99 pub fn error_rate(&self) -> f64 {
100 100.0 - self.success_rate()
101 }
102
103 #[must_use]
105 #[allow(clippy::cast_precision_loss)]
106 pub fn processing_time_seconds(&self) -> f64 {
107 self.processing_time_ms as f64 / 1000.0
108 }
109
110 #[must_use]
112 #[allow(clippy::cast_precision_loss)]
113 pub fn bytes_processed_mb(&self) -> f64 {
114 self.bytes_processed as f64 / (1024.0 * 1024.0)
115 }
116
117 pub fn set_schema_fingerprint(&mut self, fingerprint: String) {
119 self.schema_fingerprint = fingerprint;
120 }
121
122 pub fn set_peak_memory_bytes(&mut self, bytes: u64) {
124 self.peak_memory_bytes = Some(bytes);
125 }
126}
127
128impl fmt::Display for RunSummary {
129 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
130 writeln!(f, "Processing Summary:")?;
131 writeln!(f, " Records processed: {}", self.records_processed)?;
132 writeln!(f, " Records with errors: {}", self.records_with_errors)?;
133 writeln!(f, " Warnings: {}", self.warnings)?;
134 writeln!(f, " Success rate: {:.1}%", self.success_rate())?;
135 writeln!(
136 f,
137 " Processing time: {:.2}s",
138 self.processing_time_seconds()
139 )?;
140 writeln!(f, " Bytes processed: {:.2} MB", self.bytes_processed_mb())?;
141 writeln!(f, " Throughput: {:.2} MB/s", self.throughput_mbps)?;
142 writeln!(f, " Threads used: {}", self.threads_used)?;
143 if let Some(peak_memory) = self.peak_memory_bytes {
144 #[allow(clippy::cast_precision_loss)]
145 let peak_mb = peak_memory as f64 / (1024.0 * 1024.0);
146 writeln!(f, " Peak memory: {peak_mb:.2} MB")?;
147 }
148 if !self.schema_fingerprint.is_empty() {
149 writeln!(f, " Schema fingerprint: {}", self.schema_fingerprint)?;
150 }
151 Ok(())
152 }
153}