1#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
6pub struct Progress {
7 pub read_rows: u64,
8 pub read_bytes: u64,
9 pub total_rows_to_read: u64,
10 pub total_bytes_to_read: Option<u64>,
11 pub written_rows: Option<u64>,
12 pub written_bytes: Option<u64>,
13 pub elapsed_ns: Option<u64>,
14}
15
16impl std::ops::Add for Progress {
17 type Output = Progress;
18
19 fn add(self, rhs: Self) -> Self::Output {
20 let sum_opt = |opt1, opt2| match (opt1, opt2) {
21 (Some(a), Some(b)) => Some(a + b),
22 (Some(a), None) => Some(a),
23 (None, Some(b)) => Some(b),
24 (None, None) => None,
25 };
26 Self::Output {
27 read_rows: self.read_rows + rhs.read_rows,
28 read_bytes: self.read_bytes + rhs.read_bytes,
29 total_rows_to_read: self.total_rows_to_read + rhs.total_rows_to_read,
30 total_bytes_to_read: sum_opt(self.total_bytes_to_read, rhs.total_bytes_to_read),
31 written_rows: sum_opt(self.written_rows, rhs.written_rows),
32 written_bytes: sum_opt(self.written_bytes, rhs.written_bytes),
33 elapsed_ns: sum_opt(self.elapsed_ns, rhs.elapsed_ns),
34 }
35 }
36}
37
38impl std::fmt::Display for Progress {
39 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
40 write!(f, "Progress | Read | Remaining | W Rows | W Bytes | Elapsed")?;
41
42 let Self {
43 read_rows,
44 read_bytes,
45 total_rows_to_read,
46 total_bytes_to_read: _,
47 written_rows,
48 written_bytes,
49 elapsed_ns,
50 } = self;
51
52 write!(
53 f,
54 "{read_rows}/{read_bytes} | {total_rows_to_read} | {written_rows:?} | \
55 {written_bytes:?} | {elapsed_ns:?}"
56 )?;
57
58 Ok(())
59 }
60}
61
62#[cfg(test)]
63mod tests {
64 use super::*;
65
66 #[test]
67 fn test_progress_default() {
68 let progress = Progress::default();
69 assert_eq!(progress.read_rows, 0);
70 assert_eq!(progress.read_bytes, 0);
71 assert_eq!(progress.total_rows_to_read, 0);
72 assert_eq!(progress.total_bytes_to_read, None);
73 assert_eq!(progress.written_rows, None);
74 assert_eq!(progress.written_bytes, None);
75 assert_eq!(progress.elapsed_ns, None);
76 }
77
78 #[test]
79 fn test_progress_creation() {
80 let progress = Progress {
81 read_rows: 100,
82 read_bytes: 1024,
83 total_rows_to_read: 1000,
84 total_bytes_to_read: Some(10240),
85 written_rows: Some(50),
86 written_bytes: Some(512),
87 elapsed_ns: Some(1_000_000),
88 };
89
90 assert_eq!(progress.read_rows, 100);
91 assert_eq!(progress.read_bytes, 1024);
92 assert_eq!(progress.total_rows_to_read, 1000);
93 assert_eq!(progress.total_bytes_to_read, Some(10240));
94 assert_eq!(progress.written_rows, Some(50));
95 assert_eq!(progress.written_bytes, Some(512));
96 assert_eq!(progress.elapsed_ns, Some(1_000_000));
97 }
98
99 #[test]
100 fn test_progress_clone_copy() {
101 let progress = Progress {
102 read_rows: 123,
103 read_bytes: 456,
104 total_rows_to_read: 789,
105 total_bytes_to_read: Some(1011),
106 written_rows: Some(121),
107 written_bytes: Some(314),
108 elapsed_ns: Some(1516),
109 };
110
111 let cloned = progress;
112 let copied = progress;
113
114 assert_eq!(progress, cloned);
115 assert_eq!(progress, copied);
116 }
117
118 #[test]
119 fn test_progress_debug() {
120 let progress = Progress {
121 read_rows: 100,
122 read_bytes: 1024,
123 total_rows_to_read: 1000,
124 total_bytes_to_read: Some(10240),
125 written_rows: Some(50),
126 written_bytes: Some(512),
127 elapsed_ns: Some(1_000_000),
128 };
129
130 let debug_str = format!("{progress:?}");
131 assert!(debug_str.contains("Progress"));
132 assert!(debug_str.contains("100"));
133 assert!(debug_str.contains("1024"));
134 }
135
136 #[test]
137 fn test_progress_add_all_some() {
138 let progress1 = Progress {
139 read_rows: 100,
140 read_bytes: 1024,
141 total_rows_to_read: 1000,
142 total_bytes_to_read: Some(10240),
143 written_rows: Some(50),
144 written_bytes: Some(512),
145 elapsed_ns: Some(1_000_000),
146 };
147
148 let progress2 = Progress {
149 read_rows: 200,
150 read_bytes: 2048,
151 total_rows_to_read: 2000,
152 total_bytes_to_read: Some(20480),
153 written_rows: Some(100),
154 written_bytes: Some(1024),
155 elapsed_ns: Some(2_000_000),
156 };
157
158 let result = progress1 + progress2;
159
160 assert_eq!(result.read_rows, 300);
161 assert_eq!(result.read_bytes, 3072);
162 assert_eq!(result.total_rows_to_read, 3000);
163 assert_eq!(result.total_bytes_to_read, Some(30720));
164 assert_eq!(result.written_rows, Some(150));
165 assert_eq!(result.written_bytes, Some(1536));
166 assert_eq!(result.elapsed_ns, Some(3_000_000));
167 }
168
169 #[test]
170 fn test_progress_add_mixed_options() {
171 let progress1 = Progress {
172 read_rows: 100,
173 read_bytes: 1024,
174 total_rows_to_read: 1000,
175 total_bytes_to_read: Some(10240),
176 written_rows: Some(50),
177 written_bytes: None,
178 elapsed_ns: Some(1_000_000),
179 };
180
181 let progress2 = Progress {
182 read_rows: 200,
183 read_bytes: 2048,
184 total_rows_to_read: 2000,
185 total_bytes_to_read: None,
186 written_rows: None,
187 written_bytes: Some(1024),
188 elapsed_ns: None,
189 };
190
191 let result = progress1 + progress2;
192
193 assert_eq!(result.read_rows, 300);
194 assert_eq!(result.read_bytes, 3072);
195 assert_eq!(result.total_rows_to_read, 3000);
196 assert_eq!(result.total_bytes_to_read, Some(10240)); assert_eq!(result.written_rows, Some(50)); assert_eq!(result.written_bytes, Some(1024)); assert_eq!(result.elapsed_ns, Some(1_000_000)); }
201
202 #[test]
203 fn test_progress_add_all_none() {
204 let progress1 = Progress {
205 read_rows: 100,
206 read_bytes: 1024,
207 total_rows_to_read: 1000,
208 total_bytes_to_read: None,
209 written_rows: None,
210 written_bytes: None,
211 elapsed_ns: None,
212 };
213
214 let progress2 = Progress {
215 read_rows: 200,
216 read_bytes: 2048,
217 total_rows_to_read: 2000,
218 total_bytes_to_read: None,
219 written_rows: None,
220 written_bytes: None,
221 elapsed_ns: None,
222 };
223
224 let result = progress1 + progress2;
225
226 assert_eq!(result.read_rows, 300);
227 assert_eq!(result.read_bytes, 3072);
228 assert_eq!(result.total_rows_to_read, 3000);
229 assert_eq!(result.total_bytes_to_read, None); assert_eq!(result.written_rows, None); assert_eq!(result.written_bytes, None); assert_eq!(result.elapsed_ns, None); }
234
235 #[test]
236 fn test_progress_display() {
237 let progress = Progress {
238 read_rows: 100,
239 read_bytes: 1024,
240 total_rows_to_read: 1000,
241 total_bytes_to_read: Some(10240),
242 written_rows: Some(50),
243 written_bytes: Some(512),
244 elapsed_ns: Some(1_000_000),
245 };
246
247 let display_str = format!("{progress}");
248
249 assert!(display_str.contains("Progress"));
251 assert!(display_str.contains("Read"));
252 assert!(display_str.contains("Remaining"));
253 assert!(display_str.contains("W Rows"));
254 assert!(display_str.contains("W Bytes"));
255 assert!(display_str.contains("Elapsed"));
256 assert!(display_str.contains("100/1024"));
257 assert!(display_str.contains("1000"));
258 assert!(display_str.contains("Some(50)"));
259 assert!(display_str.contains("Some(512)"));
260 assert!(display_str.contains("Some(1000000)"));
261 }
262
263 #[test]
264 fn test_progress_display_with_nones() {
265 let progress = Progress {
266 read_rows: 100,
267 read_bytes: 1024,
268 total_rows_to_read: 1000,
269 total_bytes_to_read: None,
270 written_rows: None,
271 written_bytes: None,
272 elapsed_ns: None,
273 };
274
275 let display_str = format!("{progress}");
276
277 assert!(display_str.contains("None"));
279 assert!(display_str.contains("100/1024"));
280 assert!(display_str.contains("1000"));
281 }
282
283 #[test]
284 fn test_progress_equality() {
285 let progress1 = Progress {
286 read_rows: 100,
287 read_bytes: 1024,
288 total_rows_to_read: 1000,
289 total_bytes_to_read: Some(10240),
290 written_rows: Some(50),
291 written_bytes: Some(512),
292 elapsed_ns: Some(1_000_000),
293 };
294
295 let progress2 = Progress {
296 read_rows: 100,
297 read_bytes: 1024,
298 total_rows_to_read: 1000,
299 total_bytes_to_read: Some(10240),
300 written_rows: Some(50),
301 written_bytes: Some(512),
302 elapsed_ns: Some(1_000_000),
303 };
304
305 let progress3 = Progress {
306 read_rows: 200, read_bytes: 1024,
308 total_rows_to_read: 1000,
309 total_bytes_to_read: Some(10240),
310 written_rows: Some(50),
311 written_bytes: Some(512),
312 elapsed_ns: Some(1_000_000),
313 };
314
315 assert_eq!(progress1, progress2);
316 assert_ne!(progress1, progress3);
317 }
318}