neuromorphic_drivers/
configuration.rs

1pub struct Flagged<Configuration> {
2    configuration: Configuration,
3    updated: bool,
4}
5
6pub struct Updater<Configuration> {
7    flagged_configuration_and_condition:
8        std::sync::Arc<(std::sync::Mutex<Flagged<Configuration>>, std::sync::Condvar)>,
9    thread: Option<std::thread::JoinHandle<()>>,
10    running: std::sync::Arc<std::sync::atomic::AtomicBool>,
11}
12
13impl<Configuration: Clone + Send + 'static> Updater<Configuration> {
14    pub fn new<ContextType, Update>(
15        initial_configuration: Configuration,
16        context: ContextType,
17        update: Update,
18    ) -> Self
19    where
20        ContextType: Send + 'static,
21        Update: Fn(ContextType, &Configuration, &Configuration) -> ContextType + Send + 'static,
22    {
23        let previous_configuration = initial_configuration.clone();
24        let flagged_configuration_and_condition = std::sync::Arc::new((
25            std::sync::Mutex::new(Flagged {
26                configuration: initial_configuration,
27                updated: false,
28            }),
29            std::sync::Condvar::new(),
30        ));
31        let thread_flagged_configuration_and_condition =
32            flagged_configuration_and_condition.clone();
33        let running = std::sync::Arc::new(std::sync::atomic::AtomicBool::new(true));
34        let thread_running = running.clone();
35        Self {
36            flagged_configuration_and_condition,
37            thread: Some(std::thread::spawn(move || {
38                let mut context = context;
39                let mut previous_configuration = previous_configuration;
40                while thread_running.load(std::sync::atomic::Ordering::Acquire) {
41                    let configuration = {
42                        let (lock, condvar) = &*thread_flagged_configuration_and_condition;
43                        let mut flagged_configuration = lock
44                            .lock()
45                            .expect("flagged configuration mutex is not poisoned");
46                        if !flagged_configuration.updated {
47                            flagged_configuration = condvar
48                                .wait_timeout(
49                                    flagged_configuration,
50                                    std::time::Duration::from_millis(100),
51                                )
52                                .expect("flagged configuration mutex is not poisoned")
53                                .0;
54                        }
55                        if flagged_configuration.updated {
56                            flagged_configuration.updated = false;
57                            Some(flagged_configuration.configuration.clone())
58                        } else {
59                            None
60                        }
61                    };
62                    if let Some(configuration) = configuration {
63                        context = update(context, &previous_configuration, &configuration);
64                        previous_configuration = configuration;
65                    }
66                }
67            })),
68            running,
69        }
70    }
71
72    pub fn update(&self, configuration: Configuration) {
73        let (lock, condvar) = &*self.flagged_configuration_and_condition;
74        let mut flagged_configuration = lock
75            .lock()
76            .expect("flagged configuration mutex is not poisoned");
77        flagged_configuration.configuration = configuration;
78        flagged_configuration.updated = true;
79        condvar.notify_one();
80    }
81
82    pub fn current_configuration(&self) -> Configuration {
83        self.flagged_configuration_and_condition
84            .0
85            .lock()
86            .expect("flagged configuration mutex is not poisoned")
87            .configuration
88            .clone()
89    }
90}
91
92impl<Configuration> Drop for Updater<Configuration> {
93    fn drop(&mut self) {
94        self.running
95            .store(false, std::sync::atomic::Ordering::Release);
96        if let Some(thread) = self.thread.take() {
97            thread.join().expect("not joining self");
98        }
99    }
100}