1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
use std::sync::{Arc, RwLock};
#[derive(Debug)]
pub struct MutCfg<T> {
cfg: RwLock<Arc<T>>,
}
impl<T> MutCfg<T> {
pub fn new(config: T) -> Self {
Self {
cfg: RwLock::new(Arc::new(config)),
}
}
pub fn get(&self) -> Arc<T> {
Arc::clone(&self.cfg.read().expect("poisoned lock"))
}
pub fn check_and_replace(&self, old_config: &Arc<T>, new_config: T) -> bool {
let mut cfg = self.cfg.write().expect("poisoned lock");
if Arc::ptr_eq(&cfg, old_config) {
*cfg = Arc::new(new_config);
true
} else {
false
}
}
pub fn replace(&self, new_config: T) {
*self.cfg.write().expect("poisoned lock") = Arc::new(new_config);
}
pub fn map_and_replace<F>(&self, func: F)
where
F: FnOnce(&Arc<T>) -> T,
{
let mut cfg = self.cfg.write().expect("poisoned lock");
let new_cfg = func(&cfg);
*cfg = Arc::new(new_cfg);
}
}
impl<T: Default> Default for MutCfg<T> {
fn default() -> Self {
MutCfg::new(T::default())
}
}
impl<T> From<T> for MutCfg<T> {
fn from(config: T) -> MutCfg<T> {
MutCfg::new(config)
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn basic_constructors() {
let m = MutCfg::new(7_u32);
assert_eq!(*m.get(), 7);
let m: MutCfg<u32> = MutCfg::default();
assert_eq!(*m.get(), 0);
let m: MutCfg<u32> = 100.into();
assert_eq!(*m.get(), 100);
}
#[test]
fn mutate_with_existing_ref() {
let m = MutCfg::new(100_u32);
let old_ref = m.get();
m.replace(101);
assert_eq!(*old_ref, 100);
assert_eq!(*m.get(), 101);
}
#[test]
fn check_and_replace() {
let m = MutCfg::new(100_u32);
let different_100 = Arc::new(100_u32);
assert!(!m.check_and_replace(&different_100, 200));
let old_100 = m.get();
assert_eq!(*old_100, 100);
assert!(m.check_and_replace(&old_100, 200));
assert_eq!(*m.get(), 200);
}
#[test]
fn map_and_replace() {
let m = MutCfg::new(100_u32);
let m_old = m.get();
m.map_and_replace(|old_val| **old_val * 20);
assert_eq!(*m.get(), 2000);
assert_eq!(*m_old, 100);
}
}