# API Documentation ## Overview This document provides comprehensive API documentation for the Top Drives Records Analyzer, including all public functions, data structures, and their usage patterns. ## Core Modules ### Records Module (`src/records.rs`) Primary analysis engine for processing JSON-based timing data. #### Public Functions ##### `main()` **Entry point for the records analyzer** ```rust #[tokio::main] async fn main() ``` **Purpose**: Command-line interface and operation dispatcher **Arguments**: Command line arguments - `args[1]`: Command (`fetch`, `best`, `missing`, `trash`, `details`, `track`, `full_script`) **Commands**: - `fetch`: Download all data files - `best`: Show best owned cars - `missing`: Show best unowned cars - `trash`: Show removable cars - `details`: Export all timing data - `track`: Track-specific analysis - `full_script`: Run fetch + all analysis commands **Example**: ```bash cargo run --bin records -- best ``` ##### `print_best_cars(filter_out_owned: bool)` **Displays ranked list of best performing cars** ```rust fn print_best_cars(filter_out_owned: bool) ``` **Purpose**: Aggregates performance data across all tracks and conditions **Arguments**: - `filter_out_owned`: If true, excludes owned cars from output **Output Format**: ```csv RQ,Brand,Model,Year,Count 85,McLaren,F1,1993,15 82,Ferrari,250 GTO,1962,12 ``` **Algorithm**: 1. Count occurrences of each car across all track/RQ/condition combinations 2. Sort by RQ level, then by car identifier 3. Apply ownership filter if requested ##### `print_best_times()` **Exports comprehensive timing data for all combinations** ```rust fn print_best_times() ``` **Purpose**: Detailed performance export for external analysis **Output Format**: ```csv RQ,TrackID,Condition,CarRQ,Brand,Model,Year,Config,Time 85,laguna,Dry,85,McLaren,F1,1993,233,112.45 ``` **Data Volume**: Large output file with all track/condition/RQ combinations ##### `print_best_car(track: &String, condition: &String, rq: &String)` **Finds best car for specific track conditions** ```rust fn print_best_car(track: &String, condition: &String, rq: &String) ``` **Purpose**: Targeted analysis for specific racing scenarios **Arguments**: - `track`: Track identifier (e.g., "laguna", "monaco") - `condition`: Surface condition (e.g., "Dry", "Wet") - `rq`: RQ level limit **Example**: ```rust print_best_car(&"laguna".to_string(), &"Dry".to_string(), &"85".to_string()); ``` ##### `print_trash()` **Identifies cars safe for removal from collection** ```rust fn print_trash() ``` **Purpose**: Collection optimization recommendations **Safety Criteria**: - Car not among best performers on any track - RQ level below 80 (preserves high-end cars) - Not a prize car (may have collection value) **Output Format**: ```csv RQ,Brand,Model,Year 45,Toyota,Corolla,1995 ``` ##### `parse_car_times(car: Car)` **Processes timing data for a single car** ```rust async fn parse_car_times(car: Car) ``` **Purpose**: Core parsing logic for individual car performance data **Process Flow**: 1. Load car's JSON timing file 2. Parse each configuration (111, 233, 323, etc.) 3. Extract timing data for each track/condition 4. Apply quality filters (downvotes, time validation) 5. Update global best cars cache **Quality Filters**: - Minimum time: 1.2 seconds - No downvotes from community - Special handling for Test Bowl track ##### `parse_all_times()` **Orchestrates concurrent processing of all cars** ```rust async fn parse_all_times() ``` **Purpose**: Coordinates parallel processing of car timing files **Concurrency**: One async task per car file, bounded by a semaphore (limit 20) **Synchronization**: Waits for all tasks to complete ##### `update_best_car(track_id: &str, car_rq: u8, surface: &str, new_record: BestCarRecord)` **Updates global best cars database with new performance data** ```rust fn update_best_car(track_id: &str, car_rq: u8, surface: &str, new_record: BestCarRecord) ``` **Purpose**: Implements core best-car selection algorithm **RQ Range Analysis**: - Tests car from base RQ up to `MAX_RQ` (113) - Compares against existing best times - Updates records for improved performance **Logic**: 1. For each RQ level from car_rq to `MAX_RQ` (113): 2. If new time is better → replace record 3. If new time ties → add to list (if not duplicate) 4. If new time is worse → ignore ##### `get_car_list() -> Vec` **Loads complete car database from repository file** ```rust fn get_car_list() -> Vec ``` **Purpose**: Provides access to all known cars in the database **Source**: `cars_repo.json` file **Returns**: Vector of all cars with complete metadata ##### `get_my_car_list() -> Vec` **Loads user's car collection from game export** ```rust fn get_my_car_list() -> Vec ``` **Purpose**: Identifies which cars the user owns **Source**: `my_cars.json` game export **Filter**: Only `locked: true` cards **Returns**: Vector of owned car GUIDs ##### `fetch_times()` **Downloads timing files for all cars with rate limiting** ```rust async fn fetch_times() ``` **Purpose**: Batch download of car timing data **Rate Limiting**: 20 concurrent downloads maximum (semaphore) **Progress**: Shows download progress for each file ##### `fetch_car(rid: String)` **Downloads timing data for single car** ```rust async fn fetch_car(rid: String) ``` **Purpose**: Individual car data fetching **URL Format**: `https://api.topdrivesrecords.com/car/{rid}` **Storage**: `times/{rid}.json` ##### `get_cars_file()` **Downloads main car database** ```rust async fn get_cars_file() ``` **Purpose**: Updates car metadata database **Source**: GitHub repository cars database **Destination**: `cars_repo.json` ##### `get_tracks_file()` **Downloads track definitions** ```rust async fn get_tracks_file() ``` **Purpose**: Updates track name mappings **Source**: GitHub repository tracks database **Destination**: `tracks_repo.json` ##### `get_file(file_url: &str, local_file_path: &str)` **Generic file download utility** ```rust async fn get_file(file_url: &str, local_file_path: &str) ``` **Purpose**: Downloads files from remote URLs **Features**: - Automatic existing file removal - Error handling with graceful failure - Progress indication through errors ### Shared Library (`src/lib.rs`) Common utilities shared across the project. ##### `translate_track_name(track_code: &str) -> &str` **Converts track codes to human-readable names** ```rust fn translate_track_name(track_code: &str) -> &str ``` **Purpose**: User-friendly track name display **Implementation**: Loads mappings from `track_names.json` at compile time via `include_str!` **Coverage**: All tracks defined in `track_names.json` **Fallback**: Returns original code if not found ##### `translate_track_type(track_code: &str) -> &str` **Converts condition codes to surface descriptions** ```rust fn translate_track_type(track_code: &str) -> &str ``` **Purpose**: Human-readable surface condition names **Mappings**: - `"00"` → `"Dry"` - `"01"` → `"Wet"` - `"10"` → `"Dirt"` - `"11"` → `"Dirt Wet"` ##### `split_prefix_postfix<'a>(input: &'a str, delimiter: &'a str) -> Option<(&'a str, &'a str)>` **String splitting utility for track ID parsing** ```rust fn split_prefix_postfix<'a>(input: &'a str, delimiter: &'a str) -> Option<(&'a str, &'a str)> ``` **Purpose**: Parse track IDs with condition suffixes **Example**: ```rust split_prefix_postfix("laguna_a00", "_a") // Some(("laguna", "00")) ``` ## Data Structures ### Records Module Data Types #### `Card` **User's car collection entry** ```rust struct Card { cardId: String, // Unique card identifier locked: bool, // Ownership status } ``` #### `Car` **Car metadata from database** ```rust struct Car { rid: String, // Repository ID brand: String, // Manufacturer only_name: String, // Model name year: u16, // Model year rq: u8, // Rarity level prize: bool, // Prize car status guid: String, // Game GUID } ``` #### `BestCarRecord` **Performance record for best cars** ```rust struct BestCarRecord { car_rid: String, // Car identifier brand: String, // Manufacturer only_name: String, // Model name year: u16, // Year rq: u8, // RQ level config: String, // Tune configuration time: f64, // Track time owned: bool, // User ownership guid: String, // Game identifier } ``` #### `TripletKey` **Composite key for track conditions** ```rust type TripletKey = (String, u8, String); // Track ID RQ Level Surface Condition ``` ### Constants #### `MAX_RQ` ```rust const MAX_RQ: u8 = 113; ``` **Purpose**: Maximum RQ level for range analysis. Replaces former magic number 115 with a named constant. ## Global State ### `BEST_CARS` Cache **Thread-safe global performance database** ```rust static BEST_CARS: Lazy>>> ``` **Initialization**: One-time setup with `once_cell::Lazy` **Thread Safety**: Protected by `Mutex` for concurrent access **Structure**: HashMap with composite keys for efficient lookups ## Error Handling ### Network Errors - **HTTP Failures**: Logged but don't crash application - **Invalid JSON**: Graceful fallback to defaults - **Missing Files**: Clear error messages for user ### Parse Errors - **Malformed Data**: Skip invalid entries - **Type Conversion**: Use safe defaults - **Missing Fields**: Provide sensible fallbacks ### User Input Errors - **Invalid Commands**: Clear usage instructions - **Missing Arguments**: Descriptive error messages - **Out of Range**: Validation with helpful feedback ## Usage Examples ### Basic Analysis Workflow ```rust // 1. Load user's car collection let my_cars = get_my_car_list(); // 2. Process all car timing data parse_all_times().await; // 3. Generate best cars report print_best_cars(false); // 4. Find collection optimization opportunities print_trash(); ``` ### Track-Specific Analysis ```rust // Analyze specific track conditions let track = "laguna".to_string(); let condition = "Dry".to_string(); let rq = "85".to_string(); print_best_car(&track, &condition, &rq); ``` ### Data Fetching ```rust // Download fresh data get_cars_file().await; get_tracks_file().await; fetch_times().await; ``` ## Performance Characteristics ### Time Complexity - **Parsing**: O(n) where n = number of cars × tracks - **Best Car Selection**: O(1) HashMap operations - **Sorting**: O(n log n) for output ordering ### Memory Usage - **Peak**: ~200-300MB during full analysis - **Baseline**: ~50MB application overhead - **Per Car**: ~1-2KB metadata + timing data ### Concurrency - **Downloads**: 20 concurrent connections max (semaphore bounded) - **Processing**: One task per car file - **Thread Safety**: Mutex-protected shared state ## Extension Points ### Adding New Commands 1. Add command parsing in `main()` 2. Implement analysis function 3. Update help documentation ### Adding New Tracks 1. Update `tracks_repo.json` with new track definitions 2. Add track name mapping to `track_names.json` 3. Track names are compiled in at build time ### Custom Analysis Types 1. Create new output formatting functions 2. Add aggregation algorithms 3. Extend data structures as needed ## Security Considerations ### Network Security - HTTPS-only external requests - Certificate validation (with fallback) - No sensitive data transmission ### File System Security - Read-only access to game files - No modification of user data - Safe file path handling ### Input Validation - Command injection prevention - Path traversal protection - Input sanitization ## Troubleshooting API Issues ### Common Problems **"Function not found"** - Check module imports - Verify function signatures - Ensure proper visibility **"Type mismatch"** - Review struct field types - Check function signatures - Verify generic parameters **"Deadlock"** - Avoid nested Mutex locks - Check lock ordering - Use timeout where possible ### Debug Strategies **Logging**: ```rust println!("Processing car: {}", car.rid); eprintln!("Error: {}", error); ``` **Tracing**: ```rust // Add at function entry let _span = tracing::span!(Level::INFO, "function_name"); let _enter = _span.enter(); ``` **Profiling**: ```bash cargo flamegraph --bin records -- best ``` ## Migration Guide ### Version Compatibility - **Current**: 0.2.0 API stable - **Previous**: 0.1.0 fully compatible - **Future**: Semantic versioning maintained ### Breaking Changes - Club module (`src/club.rs`) has been removed - `scraper` dependency removed - `tracks.txt` removed (replaced by `track_names.json`) - Magic number 115 replaced with `const MAX_RQ: u8 = 113` - `translate_track_name()` now loads from `track_names.json` instead of hardcoded match --- **API Version**: 0.2.0 **Last Updated**: 2026-05-06 **Compatibility**: Rust 1.70.0+