//! Command dispatch and shared helpers. //! //! Provides the `run_analysis` orchestration function and `load_my_cars_or_warn` //! helper used by all command handlers. pub mod all; pub mod best; pub mod details; pub mod fetch; pub mod improve; pub mod track; pub mod trash; pub mod wishlist; use std::sync::Arc; use top_drives::{ compute_car_counts, load_my_cars_data, AnalysisContext, AppError, CarCounts, MyCarsData, }; use crate::parsing::parse_all_times; // --------------------------------------------------------------------------- // Helper: load my_cars.json with graceful degradation // --------------------------------------------------------------------------- /// Loads user car data, printing a warning and returning empty data if the file is missing. /// /// Only `MissingFile` errors are gracefully degraded — parse errors and other /// failures are propagated to the caller, because running analysis with /// silently-corrupted ownership data would produce misleading results. pub fn load_my_cars_or_warn(path: &str) -> Result { match load_my_cars_data(path) { Ok(data) => Ok(data), Err(AppError::MissingFile(msg)) => { log::warn!("{msg}"); log::warn!("Analysis will run without ownership data."); Ok(MyCarsData::default()) } Err(e) => Err(e), } } // --------------------------------------------------------------------------- // Analysis orchestration // --------------------------------------------------------------------------- /// Common analysis setup: parses all timing files and computes car counts. /// /// Takes `my_data` by value: `owned` is shared with the parse tasks via `Arc`, /// and `owned_configs`/`copy_count` are moved into [`CarCounts`]. Callers that /// need `owned` or `wishlist` after analysis must retain their own copy before /// calling this function. /// /// Returns the analysis context (for stdout commands) and the aggregated car counts /// (for CSV output commands). pub async fn run_analysis( my_data: MyCarsData, cars_db_path: &str, times_dir: &str, ) -> Result<(AnalysisContext, CarCounts), AppError> { let ctx = AnalysisContext::new(); let MyCarsData { owned, wishlist: _, owned_configs, copy_count } = my_data; let owned = Arc::new(owned); let car_list = parse_all_times(owned, &ctx, cars_db_path, times_dir).await?; let counts = compute_car_counts(&ctx, car_list, owned_configs, copy_count); Ok((ctx, counts)) }