clashmap/
util.rs

1//! Clever hacks
2
3use std::{marker::PhantomData, mem::ManuallyDrop};
4
5use lock_api::{RawRwLock, RawRwLockDowngrade, RwLockReadGuard, RwLockWriteGuard};
6
7pub(crate) fn try_map<F, T: ?Sized, U: ?Sized>(mut t: &mut T, f: F) -> Result<&mut U, &mut T>
8where
9    F: FnOnce(&mut T) -> Option<&mut U>,
10{
11    use polonius_the_crab::{polonius, polonius_return};
12    polonius!(|t| -> Result<&'polonius mut U, &mut T> {
13        if let Some(u) = f(t) {
14            polonius_return!(Ok(u));
15        }
16    });
17    Err(t)
18}
19
20/// A [`RwLockReadGuard`], without the data
21pub(crate) struct RwLockReadGuardDetached<'a, R: RawRwLock> {
22    lock: &'a R,
23    _marker: PhantomData<R::GuardMarker>,
24}
25
26impl<R: RawRwLock> Drop for RwLockReadGuardDetached<'_, R> {
27    fn drop(&mut self) {
28        // Safety: An RwLockReadGuardDetached always holds a shared lock.
29        unsafe {
30            self.lock.unlock_shared();
31        }
32    }
33}
34
35/// A [`RwLockWriteGuard`], without the data
36pub(crate) struct RwLockWriteGuardDetached<'a, R: RawRwLock> {
37    lock: &'a R,
38    _marker: PhantomData<R::GuardMarker>,
39}
40
41impl<R: RawRwLock> Drop for RwLockWriteGuardDetached<'_, R> {
42    fn drop(&mut self) {
43        // Safety: An RwLockWriteGuardDetached always holds an exclusive lock.
44        unsafe {
45            self.lock.unlock_exclusive();
46        }
47    }
48}
49
50impl<'a, R: RawRwLock> RwLockReadGuardDetached<'a, R> {
51    /// Separates the data from the [`RwLockReadGuard`]
52    ///
53    /// # Safety
54    ///
55    /// The data must not outlive the detached guard
56    pub(crate) unsafe fn detach_from<T>(guard: RwLockReadGuard<'a, R, T>) -> (Self, &'a T) {
57        let rwlock = RwLockReadGuard::rwlock(&ManuallyDrop::new(guard));
58
59        // Safety: There will be no concurrent writes as we are "forgetting" the existing guard,
60        // with the safety assumption that the caller will not drop the new detached guard early.
61        let data = unsafe { &*rwlock.data_ptr() };
62        let guard = RwLockReadGuardDetached {
63            // Safety: We are imitating the original RwLockReadGuard. It's the callers
64            // responsibility to not drop the guard early.
65            lock: unsafe { rwlock.raw() },
66            _marker: PhantomData,
67        };
68        (guard, data)
69    }
70}
71
72impl<'a, R: RawRwLock> RwLockWriteGuardDetached<'a, R> {
73    /// Separates the data from the [`RwLockWriteGuard`]
74    ///
75    /// # Safety
76    ///
77    /// The data must not outlive the detached guard
78    pub(crate) unsafe fn detach_from<T>(guard: RwLockWriteGuard<'a, R, T>) -> (Self, &'a mut T) {
79        let rwlock = RwLockWriteGuard::rwlock(&ManuallyDrop::new(guard));
80
81        // Safety: There will be no concurrent reads/writes as we are "forgetting" the existing guard,
82        // with the safety assumption that the caller will not drop the new detached guard early.
83        let data = unsafe { &mut *rwlock.data_ptr() };
84        let guard = RwLockWriteGuardDetached {
85            // Safety: We are imitating the original RwLockWriteGuard. It's the callers
86            // responsibility to not drop the guard early.
87            lock: unsafe { rwlock.raw() },
88            _marker: PhantomData,
89        };
90        (guard, data)
91    }
92}
93
94impl<'a, R: RawRwLockDowngrade> RwLockWriteGuardDetached<'a, R> {
95    /// # Safety
96    ///
97    /// The associated data must not mut mutated after downgrading
98    pub(crate) unsafe fn downgrade(self) -> RwLockReadGuardDetached<'a, R> {
99        // Do not drop the write guard - otherwise we will trigger a downgrade + unlock_exclusive,
100        // which is incorrect
101        let this = ManuallyDrop::new(self);
102
103        // Safety: An RwLockWriteGuardDetached always holds an exclusive lock.
104        unsafe { this.lock.downgrade() }
105        RwLockReadGuardDetached {
106            lock: this.lock,
107            _marker: this._marker,
108        }
109    }
110}