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<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<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>(&self, id: &<E as BorrowPrimaryKey>::BorrowedPrimaryKey) -> CryptoKeystoreResult<Option<E>>
165 where
166 E: 'static + EntityGetBorrowed + Clone + Send + Sync,
167 E::PrimaryKey: Borrow<E::BorrowedPrimaryKey>,
168 for<'a> &'a E::BorrowedPrimaryKey: KeyType,
169 {
170 <T as FetchFromDatabase>::get_borrowed::<E>(&self.arc, id).await
171 }
172
173 async fn get_unique<'a, U>(&self) -> CryptoKeystoreResult<Option<U>>
175 where
176 U: 'static + UniqueEntityExt + Entity + Clone + Send + Sync,
177 {
178 <T as FetchFromDatabase>::get_unique(&self.arc).await
179 }
180
181 async fn exists<'a, U>(&self) -> CryptoKeystoreResult<bool>
183 where
184 U: 'static + UniqueEntityExt + Entity + Clone + Send + Sync,
185 {
186 <T as FetchFromDatabase>::exists::<U>(&self.arc).await
187 }
188
189 async fn search<E, SearchKey>(&self, search_key: &SearchKey) -> CryptoKeystoreResult<Vec<E>>
191 where
192 E: 'static + Entity + SearchableEntity<SearchKey> + Clone + Send + Sync,
193 SearchKey: KeyType,
194 {
195 <T as FetchFromDatabase>::search::<E, SearchKey>(&self.arc, search_key).await
196 }
197}
198
199#[cfg(all(test, not(target_os = "unknown")))]
200mod tests {
201 use std::sync::atomic::{AtomicBool, Ordering};
202
203 use async_lock::Semaphore;
204 use futures_lite::future;
205
206 use super::UniqueArc;
207
208 #[test]
209 fn derefs_to_the_inner_value() {
210 let arc = UniqueArc::from(vec![1, 2, 3]);
211 assert_eq!(arc.len(), 3);
213 assert_eq!(&*arc, &[1, 2, 3]);
214 }
215
216 #[test]
217 fn into_inner_returns_the_value() {
218 future::block_on(async {
219 let arc = UniqueArc::from(String::from("hello"));
220 assert_eq!(UniqueArc::into_inner(arc).await, "hello");
221 });
222 }
223
224 #[test]
225 fn outstanding_weaks_do_not_block_unpacking() {
226 future::block_on(async {
227 let arc = UniqueArc::from(7_u32);
230 let _weak = UniqueArc::downgrade(&arc);
231 assert_eq!(UniqueArc::into_inner(arc).await, 7);
232 });
233 }
234
235 #[test]
236 fn upgrade_sees_the_value_while_alive() {
237 future::block_on(async {
238 let arc = UniqueArc::from(42_u32);
239 let weak = UniqueArc::downgrade(&arc);
240
241 assert_eq!(weak.upgrade().await.as_deref(), Some(&42));
243 assert_eq!(weak.upgrade_sync().as_deref(), Some(&42));
244
245 assert_eq!(*arc, 42);
247 });
248 }
249
250 #[test]
251 fn upgrade_fails_once_unpacked() {
252 future::block_on(async {
253 let arc = UniqueArc::from(42_u32);
254 let weak = UniqueArc::downgrade(&arc);
255
256 assert_eq!(UniqueArc::into_inner(arc).await, 42);
257
258 assert!(weak.upgrade().await.is_none());
260 assert!(weak.upgrade_sync().is_none());
261 });
262 }
263
264 #[test]
269 fn into_inner_waits_for_an_in_flight_upgrade() {
270 future::block_on(async {
271 let arc = UniqueArc::from(42_u32);
272 let weak = UniqueArc::downgrade(&arc);
273
274 let holding = Semaphore::new(0); let proceed = Semaphore::new(0); let unpacked = AtomicBool::new(false);
278
279 let upgrade = async {
280 let guard = weak.upgrade().await.expect("value is still alive");
281 assert_eq!(*guard, 42);
282 holding.add_permits(1);
284 proceed.acquire().await;
285 assert!(
287 !unpacked.load(Ordering::SeqCst),
288 "into_inner unpacked while an upgrade was still live"
289 );
290 *guard
291 };
293
294 let take = async {
295 holding.acquire().await;
297 proceed.add_permits(1);
300 let value = UniqueArc::into_inner(arc).await;
301 unpacked.store(true, Ordering::SeqCst);
302 value
303 };
304
305 let (upgraded, taken) = future::zip(upgrade, take).await;
306 assert_eq!(upgraded, 42);
307 assert_eq!(taken, 42);
308 });
309 }
310}