priority_lfu/guard.rs
1use std::marker::PhantomData;
2use std::ops::Deref;
3
4use parking_lot::RwLockReadGuard;
5
6/// RAII guard for borrowed values. Holds a read lock on the shard.
7///
8/// **Intentionally `!Send`** to prevent holding across `.await` points,
9/// which could cause deadlocks or excessive lock contention.
10///
11/// For async contexts, use `Cache::get_clone()` instead.
12///
13/// # Example
14///
15/// ```ignore
16/// // ✅ Good: Guard is dropped before await
17/// let data = {
18/// let guard = cache.get(&key)?;
19/// guard.some_field.clone()
20/// };
21/// some_async_fn(data).await;
22///
23/// // ✅ Good: Use get_clone() for async contexts
24/// let value = cache.get_clone(&key)?;
25/// some_async_fn(&value).await;
26///
27/// // ❌ Bad: Would hold lock across await (won't compile in Send context)
28/// let guard = cache.get(&key)?;
29/// some_async_fn().await;
30/// println!("{:?}", *guard);
31/// ```
32pub struct Guard<'a, V> {
33 /// The read lock guard (makes this type !Send automatically)
34 #[allow(unused)]
35 lock: RwLockReadGuard<'a, crate::shard::Shard>,
36 /// Pointer to the value within the locked shard
37 value: *const V,
38 /// Phantom data to tie the lifetime and type
39 marker: PhantomData<&'a V>,
40}
41
42impl<'a, V> Guard<'a, V> {
43 /// Create a new guard.
44 ///
45 /// # Safety
46 ///
47 /// The caller must ensure that `value` points to a valid `V` that lives
48 /// at least as long as the lock guard.
49 pub(crate) unsafe fn new(
50 lock: RwLockReadGuard<'a, crate::shard::Shard>,
51 value: *const V,
52 ) -> Self {
53 Self {
54 lock,
55 value,
56 marker: PhantomData,
57 }
58 }
59}
60
61// Guard is Sync (can be shared by reference across threads) but NOT Send
62// This is automatic because RwLockReadGuard from parking_lot is !Send
63unsafe impl<V: Sync> Sync for Guard<'_, V> {}
64
65// Explicitly NOT implementing Send - this is intentional!
66// The compiler automatically makes this !Send because RwLockReadGuard is !Send
67
68impl<V> Deref for Guard<'_, V> {
69 type Target = V;
70
71 fn deref(&self) -> &V {
72 // SAFETY: The guard holds a read lock on the shard, so the value is valid
73 // and won't be modified or dropped while this guard exists.
74 unsafe { &*self.value }
75 }
76}
77
78// Implement common traits for convenience
79impl<V: std::fmt::Debug> std::fmt::Debug for Guard<'_, V> {
80 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
81 (**self).fmt(f)
82 }
83}
84
85impl<V: std::fmt::Display> std::fmt::Display for Guard<'_, V> {
86 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
87 (**self).fmt(f)
88 }
89}
90
91impl<V: PartialEq> PartialEq for Guard<'_, V> {
92 fn eq(&self, other: &Self) -> bool {
93 **self == **other
94 }
95}
96
97impl<V: Eq> Eq for Guard<'_, V> {}
98
99impl<V: PartialOrd> PartialOrd for Guard<'_, V> {
100 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
101 (**self).partial_cmp(&**other)
102 }
103}
104
105impl<V: Ord> Ord for Guard<'_, V> {
106 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
107 (**self).cmp(&**other)
108 }
109}
110
111#[cfg(test)]
112mod tests {
113 use super::*;
114
115 // Test that Guard is Sync
116 #[test]
117 fn test_guard_is_sync() {
118 fn assert_sync<T: Sync>() {}
119 assert_sync::<Guard<i32>>();
120 }
121}