zng_app_context/
util.rs

1use std::{mem, ops, sync::Arc};
2
3use parking_lot::RwLock;
4
5/// Represents a read guard for an `Arc<RwLock<T>>` that owns a reference to it.
6pub struct RwLockReadGuardOwned<T: 'static> {
7    lock: parking_lot::RwLockReadGuard<'static, T>,
8    _owned: Arc<RwLock<T>>,
9}
10impl<T> RwLockReadGuardOwned<T> {
11    /// Lock owned.    
12    ///
13    /// See `parking_lot::RwLock::read` for more details.
14    pub fn lock(own: Arc<RwLock<T>>) -> Self {
15        Self {
16            // SAFETY: we cast to 'static only for storage, `lock` is dropped before `_owned`.
17            lock: unsafe { mem::transmute::<parking_lot::RwLockReadGuard<'_, T>, parking_lot::RwLockReadGuard<'static, T>>(own.read()) },
18            _owned: own,
19        }
20    }
21
22    /// Locks this `RwLock` with shared read access, blocking the current thread until it can be acquired.
23    ///
24    /// See `parking_lot::RwLock::read_recursive` for more details.
25    pub fn lock_recursive(own: Arc<RwLock<T>>) -> Self {
26        Self {
27            // SAFETY: we cast to 'static only for storage, `lock` is dropped before `_owned`.
28            lock: unsafe {
29                mem::transmute::<parking_lot::RwLockReadGuard<'_, T>, parking_lot::RwLockReadGuard<'static, T>>(own.read_recursive())
30            },
31            _owned: own,
32        }
33    }
34
35    /// Try lock owned.
36    ///
37    /// See `parking_lot::RwLock::try_read` for more details.
38    pub fn try_lock(own: Arc<RwLock<T>>) -> Option<Self> {
39        let lock = own.try_read()?;
40        Some(Self {
41            // SAFETY: we cast to 'static only for storage, `lock` is dropped before `_owned`.
42            lock: unsafe { mem::transmute::<parking_lot::RwLockReadGuard<'_, T>, parking_lot::RwLockReadGuard<'static, T>>(lock) },
43            _owned: own,
44        })
45    }
46
47    /// Try lock owned.
48    ///
49    /// See `parking_lot::RwLock::try_read` for more details.
50    pub fn try_lock_recursive(own: Arc<RwLock<T>>) -> Option<Self> {
51        let lock = own.try_read_recursive()?;
52        Some(Self {
53            // SAFETY: we cast to 'static only for storage, `lock` is dropped before `_owned`.
54            lock: unsafe { mem::transmute::<parking_lot::RwLockReadGuard<'_, T>, parking_lot::RwLockReadGuard<'static, T>>(lock) },
55            _owned: own,
56        })
57    }
58
59    /// Make a new `MappedRwLockReadGuardOwned` for a component of the locked data.
60    ///
61    /// This is an associated function that needs to be
62    /// used as `RwLockReadGuardOwned::map(...)`. A method would interfere with methods of
63    /// the same name on the contents of the locked data.
64    pub fn map<O>(guard: Self, map: impl FnOnce(&T) -> &O) -> MappedRwLockReadGuardOwned<T, O> {
65        MappedRwLockReadGuardOwned {
66            lock: parking_lot::RwLockReadGuard::map(guard.lock, map),
67            _owned: guard._owned,
68        }
69    }
70}
71impl<T> ops::Deref for RwLockReadGuardOwned<T> {
72    type Target = T;
73
74    fn deref(&self) -> &Self::Target {
75        self.lock.deref()
76    }
77}
78
79/// Represents a read guard for an `Arc<RwLock<T>>` that owns a reference to it, mapped from another read guard.
80pub struct MappedRwLockReadGuardOwned<T: 'static, O: 'static> {
81    lock: parking_lot::MappedRwLockReadGuard<'static, O>,
82    _owned: Arc<RwLock<T>>,
83}
84impl<T, O> MappedRwLockReadGuardOwned<T, O> {
85    /// Make a new `MappedRwLockReadGuardOwned` for a component of the locked data.
86    ///
87    /// This is an associated function that needs to be
88    /// used as `MappedRwLockReadGuardOwned::map(...)`. A method would interfere with methods of
89    /// the same name on the contents of the locked data.
90    pub fn map<O2>(guard: Self, map: impl FnOnce(&O) -> &O2) -> MappedRwLockReadGuardOwned<T, O2> {
91        MappedRwLockReadGuardOwned {
92            lock: parking_lot::MappedRwLockReadGuard::map(guard.lock, map),
93            _owned: guard._owned,
94        }
95    }
96}
97impl<T, O> ops::Deref for MappedRwLockReadGuardOwned<T, O> {
98    type Target = O;
99
100    fn deref(&self) -> &Self::Target {
101        self.lock.deref()
102    }
103}
104
105/// Represents a read guard for an `Arc<RwLock<T>>` that owns a reference to it.
106pub struct RwLockWriteGuardOwned<T: 'static> {
107    lock: parking_lot::RwLockWriteGuard<'static, T>,
108    _owned: Arc<RwLock<T>>,
109}
110impl<T> RwLockWriteGuardOwned<T> {
111    /// Lock owned.
112    ///
113    /// See `parking_lot::RwLock::write` for more details.
114    pub fn lock(own: Arc<RwLock<T>>) -> Self {
115        Self {
116            // SAFETY: we cast to 'static only for storage, `lock` is dropped before `_owned`.
117            lock: unsafe { mem::transmute::<parking_lot::RwLockWriteGuard<'_, T>, parking_lot::RwLockWriteGuard<'static, T>>(own.write()) },
118            _owned: own,
119        }
120    }
121
122    /// Lock owned.
123    ///
124    /// See `parking_lot::RwLock::try_write` for more details.
125    pub fn try_lock(own: Arc<RwLock<T>>) -> Option<Self> {
126        let lock = own.try_write()?;
127        Some(Self {
128            // SAFETY: we cast to 'static only for storage, `lock` is dropped before `_owned`.
129            lock: unsafe { mem::transmute::<parking_lot::RwLockWriteGuard<'_, T>, parking_lot::RwLockWriteGuard<'static, T>>(lock) },
130            _owned: own,
131        })
132    }
133
134    /// Make a new `MappedRwLockReadGuardOwned` for a component of the locked data.
135    ///
136    /// This is an associated function that needs to be
137    /// used as `MappedRwLockReadGuardOwned::map(...)`. A method would interfere with methods of
138    /// the same name on the contents of the locked data.
139    pub fn map<O>(guard: Self, map: impl FnOnce(&mut T) -> &mut O) -> MappedRwLockWriteGuardOwned<T, O> {
140        MappedRwLockWriteGuardOwned {
141            lock: parking_lot::RwLockWriteGuard::map(guard.lock, map),
142            _owned: guard._owned,
143        }
144    }
145}
146impl<T> ops::Deref for RwLockWriteGuardOwned<T> {
147    type Target = T;
148
149    fn deref(&self) -> &Self::Target {
150        self.lock.deref()
151    }
152}
153impl<T> ops::DerefMut for RwLockWriteGuardOwned<T> {
154    fn deref_mut(&mut self) -> &mut Self::Target {
155        self.lock.deref_mut()
156    }
157}
158
159/// Represents a write guard for an `Arc<RwLock<T>>` that owns a reference to it, mapped from another read guard.
160pub struct MappedRwLockWriteGuardOwned<T: 'static, O: 'static> {
161    lock: parking_lot::MappedRwLockWriteGuard<'static, O>,
162    _owned: Arc<RwLock<T>>,
163}
164impl<T, O> MappedRwLockWriteGuardOwned<T, O> {
165    /// Make a new `MappedRwLockWriteGuardOwned` for a component of the locked data.
166    ///
167    /// This is an associated function that needs to be
168    /// used as `MappedRwLockWriteGuardOwned::map(...)`. A method would interfere with methods of
169    /// the same name on the contents of the locked data.
170    pub fn map<O2>(guard: Self, map: impl FnOnce(&mut O) -> &mut O2) -> MappedRwLockWriteGuardOwned<T, O2> {
171        MappedRwLockWriteGuardOwned {
172            lock: parking_lot::MappedRwLockWriteGuard::map(guard.lock, map),
173            _owned: guard._owned,
174        }
175    }
176}
177impl<T, O> ops::Deref for MappedRwLockWriteGuardOwned<T, O> {
178    type Target = O;
179
180    fn deref(&self) -> &Self::Target {
181        self.lock.deref()
182    }
183}
184impl<T, O> ops::DerefMut for MappedRwLockWriteGuardOwned<T, O> {
185    fn deref_mut(&mut self) -> &mut Self::Target {
186        self.lock.deref_mut()
187    }
188}
189
190/// Read-only wrapper on an `Arc<RwLock<T>>` contextual value.
191pub struct ReadOnlyRwLock<T>(Arc<RwLock<T>>);
192impl<T> Clone for ReadOnlyRwLock<T> {
193    fn clone(&self) -> Self {
194        Self(self.0.clone())
195    }
196}
197impl<T> ReadOnlyRwLock<T> {
198    /// New.
199    pub fn new(l: Arc<RwLock<T>>) -> Self {
200        Self(l)
201    }
202
203    /// Locks this `RwLock` with shared read access, blocking the current thread until it can be acquired.
204    ///
205    /// See `parking_lot::RwLock::read` for more details.
206    pub fn read(&self) -> parking_lot::RwLockReadGuard<'_, T> {
207        self.0.read()
208    }
209
210    /// Locks this `RwLock` with shared read access, blocking the current thread until it can be acquired.
211    ///
212    /// Unlike `read`, this method is guaranteed to succeed without blocking if
213    /// another read lock is held at the time of the call.
214    ///
215    /// See `parking_lot::RwLock::read_recursive` for more details.
216    pub fn read_recursive(&self) -> parking_lot::RwLockReadGuard<'_, T> {
217        self.0.read_recursive()
218    }
219
220    /// Attempts to acquire this `RwLock` with shared read access.
221    ///
222    /// See `parking_lot::RwLock::try_read` for more details.
223    pub fn try_read(&self) -> Option<parking_lot::RwLockReadGuard<'_, T>> {
224        self.0.try_read()
225    }
226
227    /// Attempts to acquire this `RwLock` with shared read access.
228    ///
229    /// See `parking_lot::RwLock::try_read_recursive` for more details.
230    pub fn try_read_recursive(&self) -> Option<parking_lot::RwLockReadGuard<'_, T>> {
231        self.0.try_read_recursive()
232    }
233
234    /// Gets if the read-only shared reference is to the same lock as `other`.
235    pub fn ptr_eq(&self, other: &Self) -> bool {
236        Arc::ptr_eq(&self.0, &other.0)
237    }
238}
239
240/// Helper, runs a cleanup action once on drop.
241pub struct RunOnDrop<F: FnOnce()>(Option<F>);
242impl<F: FnOnce()> RunOnDrop<F> {
243    /// New with closure that will run once on drop.
244    pub fn new(clean: F) -> Self {
245        RunOnDrop(Some(clean))
246    }
247}
248impl<F: FnOnce()> Drop for RunOnDrop<F> {
249    fn drop(&mut self) {
250        if let Some(clean) = self.0.take() {
251            clean();
252        }
253    }
254}
255
256pub(crate) fn panic_str<'s>(payload: &'s Box<dyn std::any::Any + Send + 'static>) -> &'s str {
257    if let Some(s) = payload.downcast_ref::<&str>() {
258        s
259    } else if let Some(s) = payload.downcast_ref::<String>() {
260        s
261    } else {
262        "<unknown-panic-message-type>"
263    }
264}