trellis_runner/watchers/
mod.rs

1use std::sync::{Arc, Mutex};
2
3// #[cfg(feature = "writing")]
4// mod file;
5//
6// #[cfg(feature = "writing")]
7// pub use file::FileWriter;
8//
9// #[cfg(feature = "plotting")]
10// mod plot;
11// #[cfg(feature = "plotting")]
12// pub use plot::PlotGenerator;
13//
14mod tracing;
15
16pub enum Target {
17    Param,
18    Measure,
19}
20
21#[derive(Copy, Clone)]
22pub enum Stage {
23    Initialisation,
24    WrapUp,
25    Iteration,
26}
27
28#[derive(Clone)]
29#[allow(clippy::type_complexity)]
30pub(crate) struct ObserverVec<S>(Vec<(Arc<Mutex<dyn Observer<S>>>, Frequency)>);
31
32impl<S> ObserverVec<S> {
33    pub(crate) fn len(&self) -> usize {
34        self.0.len()
35    }
36}
37
38impl<S> Default for ObserverVec<S> {
39    fn default() -> Self {
40        Self(vec![])
41    }
42}
43
44impl<S> ObserverVec<S> {
45    pub(crate) fn as_slice(&self) -> ObserverSlice<'_, S> {
46        ObserverSlice(&self.0[..])
47    }
48}
49
50#[allow(clippy::type_complexity)]
51pub(crate) struct ObserverSlice<'a, S>(&'a [(Arc<Mutex<dyn Observer<S>>>, Frequency)]);
52
53pub trait Observer<S>: Send + Sync {
54    fn observe(&self, ident: &'static str, subject: &S, stage: Stage);
55}
56
57pub trait Observable<S> {
58    type Observer;
59    fn update(&self, ident: &'static str, subject: &S, stage: Stage);
60    fn attach(&mut self, observer: Self::Observer, frequency: Frequency);
61    fn detach(&mut self, observer: Self::Observer);
62}
63
64#[derive(Clone)]
65pub(crate) struct Subject<D> {
66    pub(crate) data: D,
67    pub(crate) observers: ObserverVec<D>,
68}
69
70impl<S> Observable<S> for ObserverVec<S> {
71    type Observer = Arc<Mutex<dyn Observer<S>>>;
72    fn update(&self, ident: &'static str, subject: &S, stage: Stage) {
73        self.0
74            .iter()
75            .map(|o| o.0.lock().unwrap())
76            .for_each(|o| o.observe(ident, subject, stage));
77    }
78    fn attach(&mut self, observer: Self::Observer, frequency: Frequency) {
79        self.0.push((observer, frequency));
80    }
81    fn detach(&mut self, observer: Self::Observer) {
82        self.0.retain(|f| !Arc::ptr_eq(&f.0, &observer));
83    }
84}
85
86#[derive(Debug, thiserror::Error)]
87pub enum ObservationError {
88    #[error("error in writer")]
89    Writer(Box<dyn std::error::Error + 'static>), // We don't wrap the actual error, as we don't want to import the deps unless requested
90}
91
92#[derive(Copy, Clone, Debug, Eq, PartialEq, Default)]
93// How often the observations should take place
94pub enum Frequency {
95    // An observer that never observes
96    #[default]
97    Never,
98    // Observations occur on every iteration
99    Always,
100    // Observations occur on every nth iteration
101    Every(usize),
102    // The observer runs during the wrap up stage only
103    OnExit,
104}