solverforge_solver/realtime/
solver_handle.rs1use std::fmt::Debug;
4use std::sync::atomic::{AtomicBool, Ordering};
5use std::sync::mpsc::{self, Receiver, Sender, TryRecvError};
6use std::sync::Arc;
7
8use solverforge_core::domain::PlanningSolution;
9
10use super::problem_change::BoxedProblemChange;
11use super::ProblemChange;
12
13#[derive(Debug, Clone, Copy, PartialEq, Eq)]
15pub enum ProblemChangeResult {
16 Queued,
18 SolverNotRunning,
20 QueueFull,
22}
23
24pub struct SolverHandle<S: PlanningSolution> {
76 change_tx: Sender<BoxedProblemChange<S>>,
78 solving: Arc<AtomicBool>,
80 terminate_early: Arc<AtomicBool>,
82}
83
84impl<S: PlanningSolution> SolverHandle<S> {
85 pub fn new() -> (Self, ProblemChangeReceiver<S>) {
89 let (tx, rx) = mpsc::channel();
90 let solving = Arc::new(AtomicBool::new(false));
91 let terminate_early = Arc::new(AtomicBool::new(false));
92
93 let handle = Self {
94 change_tx: tx,
95 solving: Arc::clone(&solving),
96 terminate_early: Arc::clone(&terminate_early),
97 };
98
99 let receiver = ProblemChangeReceiver {
100 change_rx: rx,
101 solving,
102 terminate_early,
103 };
104
105 (handle, receiver)
106 }
107
108 pub fn add_problem_change<P: ProblemChange<S> + 'static>(
112 &self,
113 change: P,
114 ) -> ProblemChangeResult {
115 if !self.solving.load(Ordering::SeqCst) {
116 return ProblemChangeResult::SolverNotRunning;
117 }
118
119 match self.change_tx.send(Box::new(change)) {
120 Ok(()) => ProblemChangeResult::Queued,
121 Err(_) => ProblemChangeResult::QueueFull,
122 }
123 }
124
125 pub fn add_problem_change_boxed(&self, change: BoxedProblemChange<S>) -> ProblemChangeResult {
127 if !self.solving.load(Ordering::SeqCst) {
128 return ProblemChangeResult::SolverNotRunning;
129 }
130
131 match self.change_tx.send(change) {
132 Ok(()) => ProblemChangeResult::Queued,
133 Err(_) => ProblemChangeResult::QueueFull,
134 }
135 }
136
137 pub fn is_solving(&self) -> bool {
138 self.solving.load(Ordering::SeqCst)
139 }
140
141 pub fn terminate_early(&self) {
145 self.terminate_early.store(true, Ordering::SeqCst);
146 }
147
148 pub fn set_solving(&self, solving: bool) {
149 self.solving.store(solving, Ordering::SeqCst);
150 }
151}
152
153impl<S: PlanningSolution> Clone for SolverHandle<S> {
154 fn clone(&self) -> Self {
155 Self {
156 change_tx: self.change_tx.clone(),
157 solving: Arc::clone(&self.solving),
158 terminate_early: Arc::clone(&self.terminate_early),
159 }
160 }
161}
162
163impl<S: PlanningSolution> Debug for SolverHandle<S> {
164 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
165 f.debug_struct("SolverHandle")
166 .field("solving", &self.solving.load(Ordering::SeqCst))
167 .field(
168 "terminate_early",
169 &self.terminate_early.load(Ordering::SeqCst),
170 )
171 .finish()
172 }
173}
174
175pub struct ProblemChangeReceiver<S: PlanningSolution> {
177 change_rx: Receiver<BoxedProblemChange<S>>,
179 solving: Arc<AtomicBool>,
181 terminate_early: Arc<AtomicBool>,
183}
184
185impl<S: PlanningSolution> ProblemChangeReceiver<S> {
186 pub fn try_recv(&self) -> Option<BoxedProblemChange<S>> {
190 match self.change_rx.try_recv() {
191 Ok(change) => Some(change),
192 Err(TryRecvError::Empty) => None,
193 Err(TryRecvError::Disconnected) => None,
194 }
195 }
196
197 pub fn drain_pending(&self) -> Vec<BoxedProblemChange<S>> {
200 let mut changes = Vec::new();
201 while let Some(change) = self.try_recv() {
202 changes.push(change);
203 }
204 changes
205 }
206
207 pub fn is_terminate_early_requested(&self) -> bool {
208 self.terminate_early.load(Ordering::SeqCst)
209 }
210
211 pub fn set_solving(&self, solving: bool) {
212 self.solving.store(solving, Ordering::SeqCst);
213 }
214
215 pub fn clear_terminate_early(&self) {
217 self.terminate_early.store(false, Ordering::SeqCst);
218 }
219}
220
221impl<S: PlanningSolution> Debug for ProblemChangeReceiver<S> {
222 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
223 f.debug_struct("ProblemChangeReceiver")
224 .field("solving", &self.solving.load(Ordering::SeqCst))
225 .finish()
226 }
227}
228
229#[cfg(test)]
230#[path = "solver_handle_tests.rs"]
231mod tests;