sorting_race/lib/
controller.rs1use crate::models::config::RunConfiguration;
4use crate::models::traits::{Sorter, FairnessModel};
5use crate::services::snapshot::SnapshotService;
6use std::time::Instant;
7
8#[derive(Debug)]
10pub struct RaceController {
11 algorithms: Vec<Box<dyn Sorter>>,
12 fairness_model: Box<dyn FairnessModel>,
13 snapshot_service: SnapshotService,
14 current_step: usize,
15 start_time: Option<Instant>,
16 is_running: bool,
17 is_paused: bool,
18}
19
20impl RaceController {
21 pub fn new(
23 algorithms: Vec<Box<dyn Sorter>>,
24 fairness_model: Box<dyn FairnessModel>,
25 max_snapshots: usize,
26 ) -> Self {
27 Self {
28 algorithms,
29 fairness_model,
30 snapshot_service: SnapshotService::new(max_snapshots),
31 current_step: 0,
32 start_time: None,
33 is_running: false,
34 is_paused: false,
35 }
36 }
37
38 pub fn start_race(&mut self, config: &RunConfiguration, data: Vec<i32>) -> Result<(), String> {
40 config.validate()?;
41
42 for algorithm in &mut self.algorithms {
44 algorithm.reset(data.clone());
45 }
46
47 self.current_step = 0;
48 self.start_time = Some(Instant::now());
49 self.is_running = true;
50 self.is_paused = false;
51 self.snapshot_service.clear();
52
53 self.snapshot_service.take_snapshot(&self.algorithms, 0);
55
56 Ok(())
57 }
58
59 pub fn step(&mut self) -> bool {
61 if !self.is_running || self.is_paused {
62 return false;
63 }
64
65 if self.is_race_complete() {
66 self.is_running = false;
67 return false;
68 }
69
70 let budgets = self.fairness_model.allocate_budget(&self.algorithms);
72
73 for (algorithm, budget) in self.algorithms.iter_mut().zip(budgets.iter()) {
75 if *budget > 0 && !algorithm.is_complete() {
76 algorithm.step(*budget);
77 }
78 }
79
80 self.current_step += 1;
81
82 self.snapshot_service.take_snapshot(&self.algorithms, self.current_step);
84
85 if self.is_race_complete() {
87 self.is_running = false;
88 }
89
90 true
91 }
92
93 pub fn run_to_completion(&mut self, max_steps: Option<usize>) -> usize {
95 let limit = max_steps.unwrap_or(usize::MAX);
96 let mut steps_executed = 0;
97
98 while self.is_running && steps_executed < limit && self.step() {
99 steps_executed += 1;
100 }
101
102 steps_executed
103 }
104
105 pub fn is_race_complete(&self) -> bool {
107 self.algorithms.iter().all(|alg| alg.is_complete())
108 }
109
110 pub fn pause(&mut self) {
112 self.is_paused = true;
113 }
114
115 pub fn resume(&mut self) {
117 self.is_paused = false;
118 }
119
120 pub fn stop(&mut self) {
122 self.is_running = false;
123 self.is_paused = false;
124 }
125
126 pub fn reset(&mut self) {
128 self.current_step = 0;
129 self.start_time = None;
130 self.is_running = false;
131 self.is_paused = false;
132 self.snapshot_service.clear();
133 }
134
135 pub fn get_current_step(&self) -> usize {
137 self.current_step
138 }
139
140 pub fn get_elapsed_time(&self) -> Option<std::time::Duration> {
142 self.start_time.map(|start| start.elapsed())
143 }
144
145 pub fn is_running(&self) -> bool {
147 self.is_running
148 }
149
150 pub fn is_paused(&self) -> bool {
152 self.is_paused
153 }
154
155 pub fn get_algorithms(&self) -> &[Box<dyn Sorter>] {
157 &self.algorithms
158 }
159
160 pub fn get_snapshot_service(&self) -> &SnapshotService {
162 &self.snapshot_service
163 }
164
165 pub fn get_snapshot_service_mut(&mut self) -> &mut SnapshotService {
167 &mut self.snapshot_service
168 }
169
170 pub fn get_fairness_model_name(&self) -> &str {
172 self.fairness_model.name()
173 }
174}