gol_core/board/
board_callback.rs

1use crate::IndexedDataOwned;
2use rayon::prelude::*;
3use std::sync::{Arc, Mutex};
4use std::thread::{self, JoinHandle};
5
6pub trait BoardCallbackWithoutStates<T, CI>: Send + Sync
7where
8    T: Send + Sync,
9    CI: Send + Sync,
10{
11    fn setup(&mut self) {}
12    fn execute(&mut self);
13    fn cleanup(&mut self) {}
14}
15
16pub trait BoardCallbackWithStates<T, CI, I>: Send + Sync
17where
18    T: Send + Sync,
19    CI: Send + Sync,
20    I: ParallelIterator<Item = IndexedDataOwned<CI, T>>,
21{
22    fn setup(&mut self) {}
23    fn execute(&mut self, states: I);
24    fn cleanup(&mut self) {}
25}
26
27pub enum BoardCallback<T, CI, I> {
28    WithoutStates(Box<dyn BoardCallbackWithoutStates<T, CI>>),
29    WithStates(Box<dyn BoardCallbackWithStates<T, CI, I>>),
30}
31
32pub struct BoardCallbackManager<T, CI, I>
33where
34    T: Send + Sync,
35    CI: Send + Sync,
36    I: ParallelIterator<Item = IndexedDataOwned<CI, T>>,
37{
38    callbacks: Arc<Mutex<Vec<BoardCallback<T, CI, I>>>>,
39    callback_handle: Arc<Mutex<Option<JoinHandle<()>>>>,
40}
41
42impl<T, CI> BoardCallbackManager<T, CI, rayon::vec::IntoIter<IndexedDataOwned<CI, T>>>
43where
44    T: 'static + Send + Sync + Clone,
45    CI: 'static + Send + Sync + Clone,
46{
47    pub fn new(
48        callbacks: Vec<BoardCallback<T, CI, rayon::vec::IntoIter<IndexedDataOwned<CI, T>>>>,
49    ) -> Self {
50        Self {
51            callbacks: Arc::new(Mutex::new(callbacks)),
52            callback_handle: Arc::new(Mutex::new(None)),
53        }
54    }
55
56    pub fn setup_all(&mut self) {
57        self.callbacks
58            .lock()
59            .unwrap()
60            .iter_mut()
61            .for_each(|ele| match ele {
62                BoardCallback::WithoutStates(val) => val.setup(),
63                BoardCallback::WithStates(val) => val.setup(),
64            });
65    }
66
67    pub fn call(&self, next_states: Vec<IndexedDataOwned<CI, T>>) {
68        self.block_until_finish();
69        debug_assert!(self.callback_handle.lock().unwrap().is_none());
70
71        let mut handle = self.callback_handle.lock().unwrap();
72        let callbacks = Arc::clone(&self.callbacks);
73        *handle = Some(thread::spawn(move || {
74            Arc::clone(&callbacks)
75                .lock()
76                .unwrap()
77                .par_iter_mut()
78                .for_each(|ele| match ele {
79                    BoardCallback::WithoutStates(val) => val.execute(),
80                    BoardCallback::WithStates(val) => {
81                        val.execute(next_states.clone().into_par_iter())
82                    }
83                });
84        }));
85    }
86
87    pub fn cleanup_all(&mut self) {
88        self.block_until_finish();
89        self.callbacks
90            .lock()
91            .unwrap()
92            .iter_mut()
93            .for_each(|ele| match ele {
94                BoardCallback::WithoutStates(val) => val.cleanup(),
95                BoardCallback::WithStates(val) => val.cleanup(),
96            });
97    }
98
99    fn block_until_finish(&self) {
100        if let Some(handle) = self.callback_handle.lock().unwrap().take() {
101            handle.join().unwrap();
102        }
103        let mut handle = self.callback_handle.lock().unwrap();
104        *handle = None;
105    }
106}