acto/
variable.rs

1use parking_lot::{RwLock, RwLockReadGuard, RwLockWriteGuard};
2use std::sync::Arc;
3
4struct Inner<T> {
5    value: RwLock<T>,
6}
7
8/// Write-side of a variable with read capability to use as single source of truth
9///
10/// Usage of [`Writer::read`] and [`Writer::write`] should be non-blocking so that readers can always
11/// quickly access the latest value.
12#[derive(Clone)]
13pub struct Writer<T>(Arc<Inner<T>>);
14
15impl<T> std::fmt::Debug for Writer<T> {
16    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
17        f.debug_tuple("Writer").finish()
18    }
19}
20
21impl<T> Writer<T> {
22    pub fn new(value: T) -> Self {
23        Self(Arc::new(Inner {
24            value: RwLock::new(value),
25        }))
26    }
27
28    pub fn write(&self) -> RwLockWriteGuard<'_, T> {
29        self.0.value.write()
30    }
31
32    pub fn read(&self) -> RwLockReadGuard<'_, T> {
33        self.0.value.read()
34    }
35
36    pub fn reader(&self) -> Reader<T> {
37        Reader(self.0.clone())
38    }
39}
40
41/// Read-side of a variable, intentionally limited to avoid blocking the writer
42#[derive(Clone)]
43pub struct Reader<T>(Arc<Inner<T>>);
44
45impl<T> Reader<T> {
46    pub fn project<U>(&self, f: impl Fn(&T) -> U) -> U {
47        let value = self.0.value.read();
48        f(&*value)
49    }
50}
51
52impl<T: Copy> Reader<T> {
53    pub fn get(&self) -> T {
54        *self.0.value.read()
55    }
56}
57
58impl<T: Clone> Reader<T> {
59    pub fn get_cloned(&self) -> T {
60        self.0.value.read().clone()
61    }
62}