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::{
13 BorrowPrimaryKey, Entity, EntityGetBorrowed, FetchFromDatabase, KeyType, SearchableEntity, UniqueEntityExt,
14 },
15};
16
17#[derive(Debug, derive_more::Deref)]
23pub struct UniqueArc<T> {
24 #[deref(forward)]
25 arc: Arc<T>,
26 gate: Arc<RwLock<()>>,
28}
29
30impl<T> From<T> for UniqueArc<T> {
31 fn from(value: T) -> Self {
32 UniqueArc {
33 arc: Arc::new(value),
34 gate: Arc::new(RwLock::new(())),
35 }
36 }
37}
38
39impl<T> UniqueArc<T> {
40 pub async fn into_inner(this: Self) -> T {
46 let UniqueArc { arc, gate } = this;
47 let _exclusive = gate.write().await;
51 Arc::into_inner(arc)
52 .expect("no other strong reference exists: `UniqueArc` is `!Clone` and all upgrades are gated")
53 }
54
55 pub fn downgrade(this: &Self) -> UniqueWeak<T> {
57 UniqueWeak {
58 weak: Arc::downgrade(&this.arc),
59 gate: Arc::clone(&this.gate),
60 }
61 }
62}
63
64#[derive(Debug, derive_more::Deref)]
73pub(crate) struct ArcWithReadGuard<T> {
74 #[deref(forward)]
75 t: Arc<T>,
76 _guard: RwLockReadGuardArc<()>,
77}
78
79#[derive(Debug)]
84pub struct UniqueWeak<T> {
85 weak: Weak<T>,
86 gate: Arc<RwLock<()>>,
89}
90
91impl<T> Clone for UniqueWeak<T> {
93 fn clone(&self) -> Self {
94 Self {
95 weak: self.weak.clone(),
96 gate: self.gate.clone(),
97 }
98 }
99}
100
101impl<T> UniqueWeak<T> {
102 pub(crate) async fn upgrade_without_type_erasure(&self) -> Option<ArcWithReadGuard<T>> {
107 let _guard = self.gate.read_arc().await;
108 self.weak.upgrade().map(move |t| ArcWithReadGuard { _guard, t })
109 }
110
111 pub async fn upgrade(&self) -> Option<impl Deref<Target = T>> {
117 self.upgrade_without_type_erasure().await
118 }
119
120 pub fn upgrade_sync(&self) -> Option<impl Deref<Target = T>> {
128 let _guard = self.gate.try_read_arc()?;
129 self.weak.upgrade().map(move |t| ArcWithReadGuard { _guard, t })
130 }
131}
132
133#[cfg_attr(target_os = "unknown", async_trait(?Send))]
134#[cfg_attr(not(target_os = "unknown"), async_trait)]
135impl<T> FetchFromDatabase for UniqueArc<T>
136where
137 T: FetchFromDatabase,
138{
139 async fn get<E>(&self, id: &E::PrimaryKey) -> CryptoKeystoreResult<Option<Arc<E>>>
141 where
142 E: 'static + Entity + Clone + Send + Sync,
143 {
144 <T as FetchFromDatabase>::get::<E>(&self.arc, id).await
145 }
146
147 async fn count<E>(&self) -> CryptoKeystoreResult<u32>
149 where
150 E: 'static + Entity + Clone + Send + Sync,
151 {
152 <T as FetchFromDatabase>::count::<E>(&self.arc).await
153 }
154
155 async fn load_all<E>(&self) -> CryptoKeystoreResult<Vec<Arc<E>>>
157 where
158 E: 'static + Entity + Clone + Send + Sync,
159 {
160 <T as FetchFromDatabase>::load_all::<E>(&self.arc).await
161 }
162
163 async fn get_borrowed<E>(
165 &self,
166 id: &<E as BorrowPrimaryKey>::BorrowedPrimaryKey,
167 ) -> CryptoKeystoreResult<Option<Arc<E>>>
168 where
169 E: 'static + EntityGetBorrowed + Clone + Send + Sync,
170 E::PrimaryKey: Borrow<E::BorrowedPrimaryKey>,
171 for<'a> &'a E::BorrowedPrimaryKey: KeyType,
172 {
173 <T as FetchFromDatabase>::get_borrowed::<E>(&self.arc, id).await
174 }
175
176 async fn get_unique<'a, U>(&self) -> CryptoKeystoreResult<Option<Arc<U>>>
178 where
179 U: 'static + UniqueEntityExt + Entity + Clone + Send + Sync,
180 {
181 <T as FetchFromDatabase>::get_unique(&self.arc).await
182 }
183
184 async fn exists<'a, U>(&self) -> CryptoKeystoreResult<bool>
186 where
187 U: 'static + UniqueEntityExt + Entity + Clone + Send + Sync,
188 {
189 <T as FetchFromDatabase>::exists::<U>(&self.arc).await
190 }
191
192 async fn search<E, SearchKey>(&self, search_key: &SearchKey) -> CryptoKeystoreResult<Vec<Arc<E>>>
194 where
195 E: 'static + Entity + SearchableEntity<SearchKey> + Clone + Send + Sync,
196 SearchKey: KeyType,
197 {
198 <T as FetchFromDatabase>::search::<E, SearchKey>(&self.arc, search_key).await
199 }
200}
201
202#[cfg(all(test, not(target_os = "unknown")))]
203mod tests {
204 use std::sync::atomic::{AtomicBool, Ordering};
205
206 use async_lock::Semaphore;
207 use futures_lite::future;
208
209 use super::UniqueArc;
210
211 #[test]
212 fn derefs_to_the_inner_value() {
213 let arc = UniqueArc::from(vec![1, 2, 3]);
214 assert_eq!(arc.len(), 3);
216 assert_eq!(&*arc, &[1, 2, 3]);
217 }
218
219 #[test]
220 fn into_inner_returns_the_value() {
221 future::block_on(async {
222 let arc = UniqueArc::from(String::from("hello"));
223 assert_eq!(UniqueArc::into_inner(arc).await, "hello");
224 });
225 }
226
227 #[test]
228 fn outstanding_weaks_do_not_block_unpacking() {
229 future::block_on(async {
230 let arc = UniqueArc::from(7_u32);
233 let _weak = UniqueArc::downgrade(&arc);
234 assert_eq!(UniqueArc::into_inner(arc).await, 7);
235 });
236 }
237
238 #[test]
239 fn upgrade_sees_the_value_while_alive() {
240 future::block_on(async {
241 let arc = UniqueArc::from(42_u32);
242 let weak = UniqueArc::downgrade(&arc);
243
244 assert_eq!(weak.upgrade().await.as_deref(), Some(&42));
246 assert_eq!(weak.upgrade_sync().as_deref(), Some(&42));
247
248 assert_eq!(*arc, 42);
250 });
251 }
252
253 #[test]
254 fn upgrade_fails_once_unpacked() {
255 future::block_on(async {
256 let arc = UniqueArc::from(42_u32);
257 let weak = UniqueArc::downgrade(&arc);
258
259 assert_eq!(UniqueArc::into_inner(arc).await, 42);
260
261 assert!(weak.upgrade().await.is_none());
263 assert!(weak.upgrade_sync().is_none());
264 });
265 }
266
267 #[test]
272 fn into_inner_waits_for_an_in_flight_upgrade() {
273 future::block_on(async {
274 let arc = UniqueArc::from(42_u32);
275 let weak = UniqueArc::downgrade(&arc);
276
277 let holding = Semaphore::new(0); let proceed = Semaphore::new(0); let unpacked = AtomicBool::new(false);
281
282 let upgrade = async {
283 let guard = weak.upgrade().await.expect("value is still alive");
284 assert_eq!(*guard, 42);
285 holding.add_permits(1);
287 proceed.acquire().await;
288 assert!(
290 !unpacked.load(Ordering::SeqCst),
291 "into_inner unpacked while an upgrade was still live"
292 );
293 *guard
294 };
296
297 let take = async {
298 holding.acquire().await;
300 proceed.add_permits(1);
303 let value = UniqueArc::into_inner(arc).await;
304 unpacked.store(true, Ordering::SeqCst);
305 value
306 };
307
308 let (upgraded, taken) = future::zip(upgrade, take).await;
309 assert_eq!(upgraded, 42);
310 assert_eq!(taken, 42);
311 });
312 }
313}