Skip to main content

rustpython_common/lock/
immutable_mutex.rs

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