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