rustpython_common/lock/
immutable_mutex.rs

1use lock_api::{MutexGuard, RawMutex};
2use std::{fmt, marker::PhantomData, ops::Deref};
3
4/// A mutex guard that has an exclusive lock, but only an immutable reference; useful if you
5/// need to map a mutex guard with a function that returns an `&T`. Construct using the
6/// [`MapImmutable`] trait.
7pub struct ImmutableMappedMutexGuard<'a, R: RawMutex, T: ?Sized> {
8    raw: &'a R,
9    data: *const T,
10    _marker: PhantomData<(&'a T, R::GuardMarker)>,
11}
12
13// main constructor for ImmutableMappedMutexGuard
14// TODO: patch lock_api to have a MappedMutexGuard::raw method, and have this implementation be for
15// MappedMutexGuard
16impl<'a, R: RawMutex, T: ?Sized> MapImmutable<'a, R, T> for MutexGuard<'a, R, T> {
17    fn map_immutable<U: ?Sized, F>(s: Self, f: F) -> ImmutableMappedMutexGuard<'a, R, U>
18    where
19        F: FnOnce(&T) -> &U,
20    {
21        let raw = unsafe { MutexGuard::mutex(&s).raw() };
22        let data = f(&s) as *const U;
23        std::mem::forget(s);
24        ImmutableMappedMutexGuard {
25            raw,
26            data,
27            _marker: PhantomData,
28        }
29    }
30}
31
32impl<'a, R: RawMutex, T: ?Sized> ImmutableMappedMutexGuard<'a, R, T> {
33    pub fn map<U: ?Sized, F>(s: Self, f: F) -> ImmutableMappedMutexGuard<'a, R, U>
34    where
35        F: FnOnce(&T) -> &U,
36    {
37        let raw = s.raw;
38        let data = f(&s) as *const U;
39        std::mem::forget(s);
40        ImmutableMappedMutexGuard {
41            raw,
42            data,
43            _marker: PhantomData,
44        }
45    }
46}
47
48impl<'a, R: RawMutex, T: ?Sized> Deref for ImmutableMappedMutexGuard<'a, R, T> {
49    type Target = T;
50    fn deref(&self) -> &Self::Target {
51        // SAFETY: self.data is valid for the lifetime of the guard
52        unsafe { &*self.data }
53    }
54}
55
56impl<'a, R: RawMutex, T: ?Sized> Drop for ImmutableMappedMutexGuard<'a, R, T> {
57    fn drop(&mut self) {
58        // SAFETY: An ImmutableMappedMutexGuard always holds the lock
59        unsafe { self.raw.unlock() }
60    }
61}
62
63impl<'a, R: RawMutex, T: fmt::Debug + ?Sized> fmt::Debug for ImmutableMappedMutexGuard<'a, R, T> {
64    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
65        fmt::Debug::fmt(&**self, f)
66    }
67}
68
69impl<'a, R: RawMutex, T: fmt::Display + ?Sized> fmt::Display
70    for ImmutableMappedMutexGuard<'a, R, T>
71{
72    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
73        fmt::Display::fmt(&**self, f)
74    }
75}
76
77pub trait MapImmutable<'a, R: RawMutex, T: ?Sized> {
78    fn map_immutable<U: ?Sized, F>(s: Self, f: F) -> ImmutableMappedMutexGuard<'a, R, U>
79    where
80        F: FnOnce(&T) -> &U;
81}