rx_rust/utils/
safe_lock.rs

1//! We use this mod to avoid deadlocks.
2//! Refer to this case: <https://stackoverflow.com/q/79621758/9315497>
3//! And this case:
4//!
5//! fn main() {
6//!    use std::sync::Mutex;
7//!    let lock = Mutex::new("My String".to_owned());
8//!    // let equals = { lock.lock().unwrap().clone() } == { lock.lock().unwrap().clone() }; // No deadlock
9//!    let equals = lock.lock().unwrap().clone() == lock.lock().unwrap().clone(); // Deadlock
10//!    println!("{}", equals);
11//! }
12//!
13//! We don't use this more common macro below, because it may cause deadlocks in Disposable of merge_all.rs.
14//!
15//! macro_rules! safe_lock {
16//!     ($lock_name:expr, $field_name:ident, $method_name:ident) => {{
17//!         use $crate::utils::types::MutableHelper;
18//!         $lock_name.lock_mut().$field_name.$method_name()
19//!     }};
20//! }
21//!
22//! The code like this may cause a deadlock:
23//! safe_lock!(self, subscriptions, clear);
24//!
25//! We use this approach: `Clone::clone(&*$lock_name.lock_ref())` instead of `$lock_name.lock_ref().clone()` to do the type checking.
26
27#[macro_export]
28macro_rules! safe_lock {
29    (clone: $lock_name:expr) => {{
30        use $crate::utils::types::MutableHelper;
31        $lock_name.lock_ref(|lock| Clone::clone(&*lock))
32    }};
33
34    (set: $lock_name:expr, $value:expr) => {{
35        use $crate::utils::types::MutableHelper;
36        let value = $value;
37        $lock_name.lock_mut(|mut lock| *lock = value)
38    }};
39
40    (mem_take: $lock_name:expr) => {{
41        use $crate::utils::types::MutableHelper;
42        $lock_name.lock_mut(|mut lock| std::mem::take(&mut *lock))
43    }};
44
45    (mem_take: $lock_name:expr, $field_name:ident) => {{
46        use $crate::utils::types::MutableHelper;
47        $lock_name.lock_mut(|mut lock| std::mem::take(&mut lock.$field_name))
48    }};
49
50    (mem_replace: $lock_name:expr, $value:expr) => {{
51        use $crate::utils::types::MutableHelper;
52        let value = $value;
53        $lock_name.lock_mut(|mut lock| std::mem::replace(&mut *lock, value))
54    }};
55
56    (mem_replace: $lock_name:expr, $field_name:ident, $value:expr) => {{
57        use $crate::utils::types::MutableHelper;
58        let value = $value;
59        $lock_name.lock_mut(|mut lock| std::mem::replace(&mut lock.$field_name, value))
60    }};
61}
62
63#[macro_export]
64macro_rules! safe_lock_option {
65    (is_none: $lock_name:expr) => {{
66        use $crate::utils::types::MutableHelper;
67        $lock_name.lock_ref(|lock| Option::is_none(&*lock))
68    }};
69
70    (is_some: $lock_name:expr) => {{
71        use $crate::utils::types::MutableHelper;
72        $lock_name.lock_ref(|lock| Option::is_some(&*lock))
73    }};
74
75    (take: $lock_name:expr) => {{
76        use $crate::utils::types::MutableHelper;
77        $lock_name.lock_mut(|mut lock| Option::take(&mut *lock))
78    }};
79
80    (take: $lock_name:expr, $field_name:ident) => {{
81        use $crate::utils::types::MutableHelper;
82        $lock_name.lock_mut(|mut lock| Option::take(&mut lock.$field_name))
83    }};
84
85    (replace: $lock_name:expr, $value:expr) => {{
86        use $crate::utils::types::MutableHelper;
87        let value = $value;
88        $lock_name.lock_mut(|mut lock| Option::replace(&mut lock, value))
89    }};
90
91    (replace: $lock_name:expr, $field_name:ident, $value:expr) => {{
92        use $crate::utils::types::MutableHelper;
93        let value = $value;
94        $lock_name.lock_mut(|mut lock| Option::replace(&mut lock.$field_name, value))
95    }};
96}
97
98#[macro_export]
99macro_rules! safe_lock_observer {
100    (on_next: $lock_name:expr, $value:expr) => {{
101        use $crate::utils::types::MutableHelper;
102        let value = $value;
103        $lock_name.lock_mut(|mut lock| Observer::on_next(&mut *lock, value))
104    }};
105}
106
107#[macro_export]
108macro_rules! safe_lock_option_observer {
109    (on_next: $lock_name:expr, $value:expr) => {{
110        use $crate::utils::types::MutableHelper;
111        let value = $value;
112        $lock_name.lock_mut(|mut lock| if let Some(observer) = lock.as_mut() {
113                Observer::on_next(observer, value);
114                true
115            } else {
116                false
117            }
118        )
119    }};
120
121    (on_next: $lock_name:expr, values: $values:expr) => {{
122        use $crate::utils::types::MutableHelper;
123        let values = $values;
124        $lock_name.lock_mut(|mut lock| if let Some(observer) = lock.as_mut() {
125                for value in values {
126                    Observer::on_next(observer, value);
127                }
128                true
129            } else {
130                false
131            }
132        )
133    }};
134
135    (on_next_and_termination: $lock_name:expr, $value:expr, $termination:expr) => {{
136        use $crate::safe_lock_option;
137        let value = $value;
138        let termination = $termination;
139        if let Some(mut observer) = safe_lock_option!(take: $lock_name) {
140            Observer::on_next(&mut observer, value);
141            Observer::on_termination(observer, termination);
142            true
143        } else {
144            false
145        }
146    }};
147
148    (on_next_and_termination: $lock_name:expr, values: $values:expr, $termination:expr) => {{
149        use $crate::safe_lock_option;
150        let values = $values;
151        let termination = $termination;
152        if let Some(mut observer) = safe_lock_option!(take: $lock_name) {
153            for value in values {
154                Observer::on_next(&mut observer, value);
155            }
156            Observer::on_termination(observer, termination);
157            true
158        } else {
159            false
160        }
161    }};
162
163    (on_termination: $lock_name:expr, $value:expr) => {{
164        use $crate::safe_lock_option;
165        if let Some(observer) = safe_lock_option!(take: $lock_name) {
166            let value = $value;
167            Observer::on_termination(observer, value);
168            true
169        } else {
170            false
171        }
172    }};
173}
174
175#[macro_export]
176macro_rules! safe_lock_option_disposable {
177    (dispose: $lock_name:expr) => {{
178        use $crate::safe_lock_option;
179        if let Some(disposable) = safe_lock_option!(take: $lock_name) {
180            Disposable::dispose(disposable);
181            true
182        } else {
183            false
184        }
185    }};
186
187    (dispose: $lock_name:expr, $field_name:ident) => {{
188        use $crate::safe_lock_option;
189        if let Some(disposable) = safe_lock_option!(take: $lock_name, $field_name) {
190            Disposable::dispose(disposable);
191            true
192        } else {
193            false
194        }
195    }};
196}
197
198#[macro_export]
199macro_rules! safe_lock_vec {
200    (is_empty: $lock_name:expr) => {{
201        use $crate::utils::types::MutableHelper;
202        $lock_name.lock_ref(|lock| Vec::is_empty(&*lock))
203    }};
204
205    (len: $lock_name:expr) => {{
206        use $crate::utils::types::MutableHelper;
207        $lock_name.lock_ref(|lock| Vec::len(&*lock))
208    }};
209
210    (push: $lock_name:expr, $value:expr) => {{
211        use $crate::utils::types::MutableHelper;
212        let value = $value;
213        $lock_name.lock_mut(|mut lock| Vec::push(&mut lock, value))
214    }};
215
216    (push: $lock_name:expr, $field_name:ident, $value:expr) => {{
217        use $crate::utils::types::MutableHelper;
218        let value = $value;
219        $lock_name.lock_mut(|mut lock| Vec::push(&mut lock.$field_name, value))
220    }};
221}
222
223#[macro_export]
224macro_rules! safe_lock_slot_map {
225    (insert: $lock_name:expr, $field_name:ident, $value:expr) => {{
226        use $crate::utils::types::MutableHelper;
227        let value = $value;
228        $lock_name.lock_mut(|mut lock| SlotMap::insert(&mut lock.$field_name, value))
229    }};
230
231    (replace: $lock_name:expr, $field_name:ident, $key:expr, $value:expr) => {{
232        use std::ops::IndexMut;
233        use $crate::utils::types::MutableHelper;
234        let key = $key;
235        let value = $value;
236        $lock_name.lock_mut(|mut lock| *SlotMap::index_mut(&mut lock.$field_name, key) = value)
237    }};
238}