artistpath_core/pathfinding/
mod.rs

1pub mod bfs;
2pub mod dijkstra;
3pub mod utils;
4
5use crate::{Algorithm, pathfinding_config::PathfindingConfig};
6use bfs::neighborhood::explore_path_neighborhood;
7use rustc_hash::FxHashMap;
8use std::time::Instant;
9use uuid::Uuid;
10
11// Type alias to reduce complexity
12type GraphData<'a> = (&'a memmap2::Mmap, &'a FxHashMap<Uuid, u64>);
13
14// Struct to group related parameters and reduce argument count
15pub struct BiDirectionalGraphs<'a> {
16    pub forward: GraphData<'a>,
17    pub reverse: GraphData<'a>,
18}
19
20// Re-export the public functions
21pub use bfs::bfs_find_path;
22pub use dijkstra::dijkstra_find_path;
23pub use utils::{EnhancedPathResult, get_artist_connections};
24
25pub fn find_paths_with_exploration(
26    start: Uuid,
27    target: Uuid,
28    algorithm: Algorithm,
29    budget: usize,
30    graphs: BiDirectionalGraphs,
31    config: &PathfindingConfig,
32) -> utils::EnhancedPathResult {
33    let search_timer = Instant::now();
34
35    // Find primary path using chosen algorithm (now bidirectional)
36    let (forward_data, forward_index) = graphs.forward;
37    let (reverse_data, reverse_index) = graphs.reverse;
38
39    let (primary_path, artists_visited, _) = match algorithm {
40        Algorithm::Dijkstra => dijkstra_find_path(
41            start,
42            target,
43            forward_data,
44            forward_index,
45            reverse_data,
46            reverse_index,
47            config,
48        ),
49        Algorithm::Bfs => bfs_find_path(
50            start,
51            target,
52            forward_data,
53            forward_index,
54            reverse_data,
55            reverse_index,
56            config,
57        ),
58    };
59
60    match primary_path {
61        Some(path) => handle_successful_path_generic(
62            path,
63            budget,
64            artists_visited,
65            BiDirectionalGraphs {
66                forward: (forward_data, forward_index),
67                reverse: (reverse_data, reverse_index),
68            },
69            config,
70            search_timer,
71        ),
72        None => utils::EnhancedPathResult::NoPath {
73            artists_visited,
74            duration_ms: search_timer.elapsed().as_millis() as u64,
75        },
76    }
77}
78
79fn handle_successful_path_generic(
80    path: Vec<(Uuid, f32)>,
81    budget: usize,
82    artists_visited: usize,
83    graphs: BiDirectionalGraphs,
84    config: &PathfindingConfig,
85    start_time: Instant,
86) -> utils::EnhancedPathResult {
87    let path_length = path.len();
88
89    if path_length > budget {
90        utils::EnhancedPathResult::PathTooLong {
91            primary_path: path,
92            path_length,
93            minimum_budget_needed: path_length,
94            artists_visited,
95            duration_ms: start_time.elapsed().as_millis() as u64,
96        }
97    } else {
98        let (related_artists, connections) =
99            explore_path_neighborhood(&path, budget, graphs, config);
100
101        utils::EnhancedPathResult::Success {
102            primary_path: path,
103            related_artists,
104            connections,
105            artists_visited,
106            duration_ms: start_time.elapsed().as_millis() as u64,
107        }
108    }
109}