atuin_common/sync/
eager_future_cell.rs1use std::future::Future;
2use std::sync::Arc;
3
4use parking_lot::Mutex;
5use tokio::runtime::Handle;
6use tokio::sync::{Notify, OnceCell};
7use tokio::task::AbortHandle;
8
9pub type EagerFutureCell<T> = EagerFuture<OnceCell<T>>;
15
16pub type MutEagerFutureCell<T> = EagerFuture<Mutex<Option<T>>>;
20
21impl<T: Clone + Send + Sync + 'static> MutEagerFutureCell<T> {
22 pub fn overwrite(&self, value: T) {
25 self.abort.abort();
26 *self.inner.cell.lock() = Some(value);
27 self.inner.ready.notify_waiters();
28 }
29}
30
31pub trait ResultCell: Default + Send + Sync + 'static {
33 type Value: Clone + Send + Sync + 'static;
34
35 fn fill(&self, value: Self::Value);
37
38 fn peek(&self) -> Option<Self::Value>;
40}
41
42impl<T: Clone + Send + Sync + 'static> ResultCell for OnceCell<T> {
43 type Value = T;
44
45 fn fill(&self, value: T) {
46 let _ = self.set(value);
47 }
48
49 fn peek(&self) -> Option<T> {
50 self.get().cloned()
51 }
52}
53
54impl<T: Clone + Send + Sync + 'static> ResultCell for Mutex<Option<T>> {
55 type Value = T;
56
57 fn fill(&self, value: T) {
58 let mut slot = self.lock();
59 if slot.is_none() {
61 *slot = Some(value);
62 }
63 }
64
65 fn peek(&self) -> Option<T> {
66 self.lock().clone()
67 }
68}
69
70#[derive(Debug)]
72struct Inner<C> {
73 cell: C,
74 ready: Notify,
75}
76
77pub struct EagerFuture<C> {
82 inner: Arc<Inner<C>>,
83 abort: AbortHandle,
84}
85
86impl<C> Clone for EagerFuture<C> {
87 fn clone(&self) -> Self {
88 Self {
89 inner: Arc::clone(&self.inner),
90 abort: self.abort.clone(),
91 }
92 }
93}
94
95impl<C> std::fmt::Debug for EagerFuture<C> {
96 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
97 f.debug_struct("EagerFuture").finish_non_exhaustive()
98 }
99}
100
101impl<C: ResultCell> EagerFuture<C> {
102 pub fn new<Fut>(work: Fut, handle: &Handle) -> Self
104 where
105 Fut: Future<Output = C::Value> + Send + 'static,
106 {
107 let inner = Arc::new(Inner {
108 cell: C::default(),
109 ready: Notify::new(),
110 });
111
112 let driver = Arc::clone(&inner);
114 let task = handle.spawn(async move {
115 let value = work.await;
116 driver.cell.fill(value);
117 driver.ready.notify_waiters();
118 });
119
120 Self {
121 inner,
122 abort: task.abort_handle(),
123 }
124 }
125
126 pub async fn get(&self) -> C::Value {
128 if let Some(value) = self.inner.cell.peek() {
129 return value;
130 }
131
132 loop {
133 let notified = self.inner.ready.notified();
134 tokio::pin!(notified);
135 notified.as_mut().enable();
136
137 if let Some(value) = self.inner.cell.peek() {
138 return value;
139 }
140
141 notified.await;
142 }
143 }
144}
145
146#[cfg(test)]
147mod tests {
148 use std::sync::Arc;
149 use std::sync::atomic::{AtomicUsize, Ordering};
150 use std::time::Duration;
151
152 use rstest::rstest;
153
154 use super::{EagerFutureCell, MutEagerFutureCell};
155
156 #[rstest]
157 #[case(42)]
158 #[case(7)]
159 #[tokio::test]
160 async fn computes_once_and_caches(#[case] value: usize) {
161 let calls = Arc::new(AtomicUsize::new(0));
162 let counter = calls.clone();
163 let cell: EagerFutureCell<usize> = EagerFutureCell::new(
164 async move {
165 counter.fetch_add(1, Ordering::SeqCst);
166 value
167 },
168 &tokio::runtime::Handle::current(),
169 );
170
171 assert_eq!(cell.get().await, value);
174 assert_eq!(cell.get().await, value);
175 assert_eq!(calls.load(Ordering::SeqCst), 1);
176 }
177
178 #[rstest]
179 fn constructs_from_a_handle_outside_the_runtime() {
180 let calls = Arc::new(AtomicUsize::new(0));
183 let counter = calls.clone();
184 let rt = tokio::runtime::Runtime::new().unwrap();
185 let cell: EagerFutureCell<usize> = EagerFutureCell::new(
186 async move {
187 counter.fetch_add(1, Ordering::SeqCst);
188 7usize
189 },
190 rt.handle(),
191 );
192
193 assert_eq!(rt.block_on(cell.get()), 7);
194 assert_eq!(calls.load(Ordering::SeqCst), 1);
195 }
196
197 #[rstest]
198 #[tokio::test]
199 async fn overwrite_supersedes_a_slow_future() {
200 let ran = Arc::new(AtomicUsize::new(0));
201 let counter = ran.clone();
202 let cell: MutEagerFutureCell<usize> = MutEagerFutureCell::new(
203 async move {
204 tokio::time::sleep(Duration::from_secs(30)).await;
206 counter.fetch_add(1, Ordering::SeqCst);
207 1
208 },
209 &tokio::runtime::Handle::current(),
210 );
211
212 cell.overwrite(2);
213
214 assert_eq!(cell.get().await, 2);
216 assert_eq!(ran.load(Ordering::SeqCst), 0);
217 }
218
219 #[rstest]
220 #[tokio::test]
221 async fn overwrite_replaces_an_already_completed_future() {
222 let cell: MutEagerFutureCell<usize> =
223 MutEagerFutureCell::new(async move { 1 }, &tokio::runtime::Handle::current());
224
225 assert_eq!(cell.get().await, 1);
227 cell.overwrite(2);
228 assert_eq!(cell.get().await, 2);
229 }
230}