Skip to main content

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}