1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
use crate::sync::RawMutex;
use std::any::{Any, TypeId};
use std::fmt::{Debug, Formatter};
use std::marker::PhantomData;
use std::mem::ManuallyDrop;
use std::ops::Deref;
/// used as wrapper for a pointer to a reference
#[must_use = "if unused the Mutex will immediately unlock"]
pub struct WatchGuardRef<'a, T: ?Sized> {
data: *const T,
lock: *const RawMutex,
marker: PhantomData<&'a T>,
}
unsafe impl<T: ?Sized + Sync> Sync for WatchGuardRef<'_, T> {}
unsafe impl<T: ?Sized + Send> Send for WatchGuardRef<'_, T> {}
impl<'mutex, T: ?Sized> WatchGuardRef<'mutex, T> {
///create a new WatchGuard from a &mut T and AnyRef
pub(crate) fn new(ptr: &'mutex T, lock: *const RawMutex) -> WatchGuardRef<'mutex, T> {
Self {
data: ptr,
lock,
marker: PhantomData,
}
}
pub fn is_locked(&self) -> bool {
unsafe { (*self.lock).is_locked() }
}
}
impl<'mutex, T: Sized> WatchGuardRef<'mutex, T> {
/// Attempts to downcast the inner value to a specific type `U`.
///
/// # Safety
/// This function is **highly unsafe** and should only be used under very specific circumstances:
/// 1. The `WatchGuard` must have been constructed over a `Box::new(pointer)` stored as `Box<dyn Any>`.
/// 2. The type stored inside the `Box` must actually match the requested type `U`.
/// 3. Violating these assumptions can lead to undefined behavior, including invalid memory access or data corruption.
///
/// # Usage Notes
/// - This is **not a general-purpose downcast**. It only works when the inner data is a `Box<dyn Any>`
/// because it relies on raw pointer dereferencing to access the inner value.
/// - `downcast_ref` returns `Some(WatchGuardRef<'mutex, U>)` if the type matches, otherwise `None`.
/// - The caller must ensure that the original `Box<dyn Any>` is valid for the lifetime `'mutex`.
/// - Cloning of the internal lock is done to maintain guard semantics safely.
///
/// # Usage case
/// - To decapsulate an internal value stored as `Box<dyn Any>` and access it as a concrete type.
/// - Safely preserves lock/guard semantics while exposing the inner value.
pub unsafe fn downcast<U: Any>(
this: WatchGuardRef<'mutex, T>,
) -> Result<WatchGuardRef<'mutex, U>, WatchGuardRef<'mutex, T>>
where
T: Any + 'mutex,
U: Any + 'mutex,
{
let this = ManuallyDrop::new(this);
// First, check if the stored type is a pointer to Box<dyn Any>.
// This ensures that we are only attempting a downcast if the inner value is a Box<dyn Any>.
if TypeId::of::<*const Box<dyn Any>>() != this.data.type_id() {
return Err(ManuallyDrop::into_inner(this));
}
// SAFETY: At this point, we assume that `self.data` is actually a `*const Box<dyn Any>`.
// Dereferencing a raw pointer is unsafe, so the caller must guarantee the invariant:
// The underlying data was originally created as `Box<dyn Any>`.
let data = this.data as *const Box<dyn Any>;
// SAFETY: Now we dereference the Box to access the inner value.
// This is critically unsafe and works only if `data` truly points to a valid `Box<dyn Any>`.
let data = unsafe { &**data };
if TypeId::of::<U>() == data.type_id() {
// SAFETY: We are casting from `dyn Any` to `U`.
// Safe only because we just checked that the type IDs match.
let data = unsafe { &*(data as *const dyn Any as *const U) };
Ok(WatchGuardRef::new(data, this.lock))
} else {
Err(ManuallyDrop::into_inner(this))
}
}
}
impl<T: ?Sized> Deref for WatchGuardRef<'_, T> {
type Target = T;
fn deref(&self) -> &T {
debug_assert!(unsafe { (*self.lock).is_locked_shared() }, "{:?}", unsafe {
&*self.lock
});
unsafe { &*self.data }
}
}
impl<T: ?Sized> Drop for WatchGuardRef<'_, T> {
#[inline]
fn drop(&mut self) {
unsafe { (*self.lock).unlock_shared() };
}
}
impl<'a, T, U> PartialEq<U> for WatchGuardRef<'a, T>
where
T: PartialEq<U> + ?Sized,
{
fn eq(&self, other: &U) -> bool {
unsafe { &*self.data == other }
}
}
impl<'a, T: Debug> Debug for WatchGuardRef<'a, T> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.debug_struct("WatchGuardRef")
.field("data", &self.data)
.field("lock", &unsafe { &*self.lock })
.finish()
}
}