core_crypto_keystore/
unique_arc.rs1use std::{
2 borrow::Borrow,
3 ops::Deref,
4 sync::{Arc, Weak},
5};
6
7use async_lock::{RwLock, RwLockReadGuardArc};
8use async_trait::async_trait;
9
10use crate::{
11 CryptoKeystoreResult,
12 traits::{BorrowPrimaryKey, Entity, EntityGetBorrowed, FetchFromDatabase, SearchableEntity, UniqueEntityExt},
13};
14
15#[derive(Debug, derive_more::Deref)]
21pub struct UniqueArc<T> {
22 #[deref(forward)]
23 arc: Arc<T>,
24 gate: Arc<RwLock<()>>,
26}
27
28impl<T> From<T> for UniqueArc<T> {
29 fn from(value: T) -> Self {
30 UniqueArc {
31 arc: Arc::new(value),
32 gate: Arc::new(RwLock::new(())),
33 }
34 }
35}
36
37impl<T> UniqueArc<T> {
38 pub async fn into_inner(this: Self) -> T {
44 let UniqueArc { arc, gate } = this;
45 let _exclusive = gate.write().await;
49 Arc::into_inner(arc)
50 .expect("no other strong reference exists: `UniqueArc` is `!Clone` and all upgrades are gated")
51 }
52
53 pub fn downgrade(this: &Self) -> UniqueWeak<T> {
55 UniqueWeak {
56 weak: Arc::downgrade(&this.arc),
57 gate: Arc::clone(&this.gate),
58 }
59 }
60}
61
62#[derive(Debug, derive_more::Deref)]
71pub(crate) struct ArcWithReadGuard<T> {
72 #[deref(forward)]
73 t: Arc<T>,
74 _guard: RwLockReadGuardArc<()>,
75}
76
77#[derive(Debug)]
82pub struct UniqueWeak<T> {
83 weak: Weak<T>,
84 gate: Arc<RwLock<()>>,
87}
88
89impl<T> Clone for UniqueWeak<T> {
91 fn clone(&self) -> Self {
92 Self {
93 weak: self.weak.clone(),
94 gate: self.gate.clone(),
95 }
96 }
97}
98
99impl<T> UniqueWeak<T> {
100 pub(crate) async fn upgrade_without_type_erasure(&self) -> Option<ArcWithReadGuard<T>> {
105 let _guard = self.gate.read_arc().await;
106 self.weak.upgrade().map(move |t| ArcWithReadGuard { _guard, t })
107 }
108
109 pub async fn upgrade(&self) -> Option<impl Deref<Target = T>> {
115 self.upgrade_without_type_erasure().await
116 }
117
118 pub fn upgrade_sync(&self) -> Option<impl Deref<Target = T>> {
126 let _guard = self.gate.try_read_arc()?;
127 self.weak.upgrade().map(move |t| ArcWithReadGuard { _guard, t })
128 }
129}
130
131#[cfg_attr(target_os = "unknown", async_trait(?Send))]
132#[cfg_attr(not(target_os = "unknown"), async_trait)]
133impl<T> FetchFromDatabase for UniqueArc<T>
134where
135 T: FetchFromDatabase,
136{
137 async fn get<E>(&self, id: &E::PrimaryKey) -> CryptoKeystoreResult<Option<Arc<E>>>
139 where
140 E: 'static + Entity + Clone + Send + Sync,
141 {
142 <T as FetchFromDatabase>::get::<E>(&self.arc, id).await
143 }
144
145 async fn count<E>(&self) -> CryptoKeystoreResult<u32>
147 where
148 E: 'static + Entity + Clone + Send + Sync,
149 {
150 <T as FetchFromDatabase>::count::<E>(&self.arc).await
151 }
152
153 async fn load_all<E>(&self) -> CryptoKeystoreResult<Vec<Arc<E>>>
155 where
156 E: 'static + Entity + Clone + Send + Sync,
157 {
158 <T as FetchFromDatabase>::load_all::<E>(&self.arc).await
159 }
160
161 async fn get_borrowed<E>(
163 &self,
164 id: &<E as BorrowPrimaryKey>::BorrowedPrimaryKey,
165 ) -> CryptoKeystoreResult<Option<Arc<E>>>
166 where
167 E: 'static + EntityGetBorrowed + Clone + Send + Sync,
168 E::PrimaryKey: Borrow<E::BorrowedPrimaryKey>,
169 <E as BorrowPrimaryKey>::BorrowedPrimaryKey: 'static + Send + Sync,
170 {
171 <T as FetchFromDatabase>::get_borrowed::<E>(&self.arc, id).await
172 }
173
174 async fn get_unique<'a, U>(&self) -> CryptoKeystoreResult<Option<Arc<U>>>
176 where
177 U: 'static + UniqueEntityExt + Entity + Clone + Send + Sync,
178 {
179 <T as FetchFromDatabase>::get_unique(&self.arc).await
180 }
181
182 async fn exists<'a, U>(&self) -> CryptoKeystoreResult<bool>
184 where
185 U: 'static + UniqueEntityExt + Entity + Clone + Send + Sync,
186 {
187 <T as FetchFromDatabase>::exists::<U>(&self.arc).await
188 }
189
190 async fn search<E, SearchKey>(&self, search_key: &SearchKey) -> CryptoKeystoreResult<Vec<Arc<E>>>
192 where
193 E: 'static + Entity + SearchableEntity<SearchKey> + Clone + Send + Sync,
194 SearchKey: Send + Sync,
195 {
196 <T as FetchFromDatabase>::search::<E, SearchKey>(&self.arc, search_key).await
197 }
198}
199
200#[cfg(all(test, not(target_os = "unknown")))]
201mod tests {
202 use std::sync::atomic::{AtomicBool, Ordering};
203
204 use async_lock::Semaphore;
205 use futures_lite::future;
206
207 use super::UniqueArc;
208
209 #[test]
210 fn derefs_to_the_inner_value() {
211 let arc = UniqueArc::from(vec![1, 2, 3]);
212 assert_eq!(arc.len(), 3);
214 assert_eq!(&*arc, &[1, 2, 3]);
215 }
216
217 #[test]
218 fn into_inner_returns_the_value() {
219 future::block_on(async {
220 let arc = UniqueArc::from(String::from("hello"));
221 assert_eq!(UniqueArc::into_inner(arc).await, "hello");
222 });
223 }
224
225 #[test]
226 fn outstanding_weaks_do_not_block_unpacking() {
227 future::block_on(async {
228 let arc = UniqueArc::from(7_u32);
231 let _weak = UniqueArc::downgrade(&arc);
232 assert_eq!(UniqueArc::into_inner(arc).await, 7);
233 });
234 }
235
236 #[test]
237 fn upgrade_sees_the_value_while_alive() {
238 future::block_on(async {
239 let arc = UniqueArc::from(42_u32);
240 let weak = UniqueArc::downgrade(&arc);
241
242 assert_eq!(weak.upgrade().await.as_deref(), Some(&42));
244 assert_eq!(weak.upgrade_sync().as_deref(), Some(&42));
245
246 assert_eq!(*arc, 42);
248 });
249 }
250
251 #[test]
252 fn upgrade_fails_once_unpacked() {
253 future::block_on(async {
254 let arc = UniqueArc::from(42_u32);
255 let weak = UniqueArc::downgrade(&arc);
256
257 assert_eq!(UniqueArc::into_inner(arc).await, 42);
258
259 assert!(weak.upgrade().await.is_none());
261 assert!(weak.upgrade_sync().is_none());
262 });
263 }
264
265 #[test]
270 fn into_inner_waits_for_an_in_flight_upgrade() {
271 future::block_on(async {
272 let arc = UniqueArc::from(42_u32);
273 let weak = UniqueArc::downgrade(&arc);
274
275 let holding = Semaphore::new(0); let proceed = Semaphore::new(0); let unpacked = AtomicBool::new(false);
279
280 let upgrade = async {
281 let guard = weak.upgrade().await.expect("value is still alive");
282 assert_eq!(*guard, 42);
283 holding.add_permits(1);
285 proceed.acquire().await;
286 assert!(
288 !unpacked.load(Ordering::SeqCst),
289 "into_inner unpacked while an upgrade was still live"
290 );
291 *guard
292 };
294
295 let take = async {
296 holding.acquire().await;
298 proceed.add_permits(1);
301 let value = UniqueArc::into_inner(arc).await;
302 unpacked.store(true, Ordering::SeqCst);
303 value
304 };
305
306 let (upgraded, taken) = future::zip(upgrade, take).await;
307 assert_eq!(upgraded, 42);
308 assert_eq!(taken, 42);
309 });
310 }
311}