tor_config/
mut_cfg.rs
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_duration_subtraction)]
76 #![allow(clippy::useless_vec)]
77 #![allow(clippy::needless_pass_by_value)]
78 use super::*;
80
81 #[test]
82 fn basic_constructors() {
83 let m = MutCfg::new(7_u32);
84 assert_eq!(*m.get(), 7);
85 let m: MutCfg<u32> = MutCfg::default();
86 assert_eq!(*m.get(), 0);
87 let m: MutCfg<u32> = 100.into();
88 assert_eq!(*m.get(), 100);
89 }
90
91 #[test]
92 fn mutate_with_existing_ref() {
93 let m = MutCfg::new(100_u32);
94 let old_ref = m.get();
95 m.replace(101);
96 assert_eq!(*old_ref, 100);
97 assert_eq!(*m.get(), 101);
98 }
99
100 #[test]
101 fn check_and_replace() {
102 let m = MutCfg::new(100_u32);
103 let different_100 = Arc::new(100_u32);
104 assert!(!m.check_and_replace(&different_100, 200));
106 let old_100 = m.get();
107 assert_eq!(*old_100, 100);
108 assert!(m.check_and_replace(&old_100, 200));
109 assert_eq!(*m.get(), 200);
110 }
111
112 #[test]
113 fn map_and_replace() {
114 let m = MutCfg::new(100_u32);
115 let m_old = m.get();
116 m.map_and_replace(|old_val| **old_val * 20);
117 assert_eq!(*m.get(), 2000);
118 assert_eq!(*m_old, 100);
119 }
120}