(shared: &SharedArgs, pricing: &PricingMap)
| 20 | } |
| 21 | |
| 22 | fn load_entries_inner(shared: &SharedArgs, pricing: &PricingMap) -> Result<Vec<LoadedEntry>> { |
| 23 | let tz = parse_tz(shared.timezone.as_deref()); |
| 24 | let mut files = discover_chat_files()?; |
| 25 | files.sort(); |
| 26 | // Read files in parallel but apply the last-wins dedup sequentially over the |
| 27 | // original (sorted) file order, so the surviving entry per dedup key is |
| 28 | // identical to the single-threaded read. |
| 29 | let loaded = read_files_parallel(&files, shared.single_thread, |file| { |
| 30 | load_chat_file(file).unwrap_or_else(|error| { |
| 31 | debug_log( |
| 32 | shared, |
| 33 | format!( |
| 34 | "Failed to read Codebuff chat file {}: {error}", |
| 35 | file.display() |
| 36 | ), |
| 37 | ); |
| 38 | Vec::new() |
| 39 | }) |
| 40 | }); |
| 41 | let mut deduped = HashMap::<String, CodebuffEntry>::new(); |
| 42 | for file_entries in loaded { |
| 43 | for entry in file_entries { |
| 44 | deduped.insert(entry.dedup_key.clone(), entry); |
| 45 | } |
| 46 | } |
| 47 | let mut entries = deduped |
| 48 | .into_values() |
| 49 | .map(|entry| to_loaded_entry(entry, tz.as_ref(), pricing)) |
| 50 | .collect::<Vec<_>>(); |
| 51 | entries.sort_by_key(|entry| entry.timestamp); |
| 52 | Ok(entries) |
| 53 | } |
| 54 | |
| 55 | fn to_loaded_entry( |
| 56 | entry: CodebuffEntry, |
no test coverage detected