async_lazy/lib.rs
1#![forbid(unsafe_op_in_unsafe_fn)]
2#![warn(
3 missing_docs,
4 rust_2018_idioms,
5 clippy::cargo,
6 clippy::semicolon_if_nothing_returned
7)]
8#![cfg_attr(feature = "nightly", feature(doc_cfg, impl_trait_in_assoc_type))]
9#![doc = include_str!("../README.md")]
10use std::{
11 cell::UnsafeCell,
12 fmt,
13 future::Future,
14 mem::ManuallyDrop,
15 ops::Drop,
16 panic::{RefUnwindSafe, UnwindSafe},
17 pin::Pin,
18 sync::atomic::{AtomicBool, Ordering},
19};
20use tokio::sync::{Semaphore, SemaphorePermit};
21
22enum LazyUninitData<Fut, F> {
23 Function(ManuallyDrop<F>),
24 Future(ManuallyDrop<Fut>),
25}
26
27/// The inner data of a `Lazy`.
28/// Is `function` when not yet initialized,
29/// `value` with `Some` when initialized,
30/// and `value` with `None` when poisoned.
31union LazyData<T, F, Fut> {
32 init: ManuallyDrop<Option<T>>,
33 uninit: ManuallyDrop<LazyUninitData<F, Fut>>,
34}
35
36/// A value that is initialized on the first access.
37/// The initialization procedure is allowed to be asycnhronous,
38/// so access to the value requires an `await`.
39///
40/// # Example
41///
42/// ```
43/// use std::time::Duration;
44/// use async_lazy::Lazy;
45///
46/// async fn some_computation() -> u32 {
47/// tokio::time::sleep(Duration::from_secs(1)).await;
48/// 1 + 1
49/// }
50///
51/// #[tokio::main]
52/// async fn main() {
53/// let lazy : Lazy<u32> = Lazy::new(|| Box::pin(async { some_computation().await }));
54///
55/// let result = tokio::spawn(async move {
56/// *lazy.force().await
57/// }).await.unwrap();
58///
59/// assert_eq!(result, 2);
60/// }
61/// ```
62pub struct Lazy<T, Fut = Pin<Box<dyn Future<Output = T> + Send>>, F = fn() -> Fut> {
63 value_set: AtomicBool,
64 value: UnsafeCell<LazyData<T, Fut, F>>,
65 semaphore: Semaphore,
66}
67
68impl<T, Fut, F> Lazy<T, Fut, F> {
69 /// Creates a new `Lazy` instance with the given initializing
70 /// async function.
71 ///
72 /// Equivalent to `Lazy::new`, except that it can be used in static
73 /// variables.
74 ///
75 /// # Example
76 ///
77 /// ```
78 /// use std::time::Duration;
79 /// use async_lazy::Lazy;
80 ///
81 /// async fn some_computation() -> u32 {
82 /// tokio::time::sleep(Duration::from_secs(1)).await;
83 /// 1 + 1
84 /// }
85 ///
86 /// static LAZY: Lazy<u32> = Lazy::new(|| Box::pin(async { some_computation().await }));
87 ///
88 /// #[tokio::main]
89 /// async fn main() {
90 /// let result = tokio::spawn(async {
91 /// *LAZY.force().await
92 /// }).await.unwrap();
93 ///
94 /// assert_eq!(result, 2);
95 /// }
96 /// ```
97 #[must_use]
98 #[inline]
99 pub const fn new(init: F) -> Self {
100 Self {
101 value_set: AtomicBool::new(false),
102 value: UnsafeCell::new(LazyData {
103 uninit: ManuallyDrop::new(LazyUninitData::Function(ManuallyDrop::new(init))),
104 }),
105 semaphore: Semaphore::const_new(1),
106 }
107 }
108
109 #[deprecated(note = "use `new` instead")]
110 #[doc(hidden)]
111 #[must_use]
112 #[inline]
113 pub const fn const_new(init: F) -> Self {
114 Self::new(init)
115 }
116
117 /// Returns `true` if this `Lazy` has been initialized, and `false` otherwise.
118 #[must_use]
119 #[inline]
120 fn initialized(&self) -> bool {
121 self.value_set.load(Ordering::Acquire)
122 }
123
124 /// Returns `true` if this `Lazy` has been initialized, and `false` otherwise.
125 /// Because it takes a mutable reference, it doesn't require an atomic operation.
126 #[must_use]
127 #[inline]
128 fn initialized_mut(&mut self) -> bool {
129 *self.value_set.get_mut()
130 }
131
132 /// Returns `true` if this `Lazy` has been initialized, and `false` otherwise.
133 /// Because it takes a mutable reference, it doesn't require an atomic operation.
134 #[must_use]
135 #[inline]
136 fn initialized_pin_mut(self: Pin<&mut Self>) -> bool {
137 // SAFETY: this doens't move out of any pinned
138 unsafe { *self.get_unchecked_mut().value_set.get_mut() }
139 }
140
141 /// Returns a reference to the value,
142 /// or `None` if it has been poisoned.
143 ///
144 /// # Safety
145 ///
146 /// The `Lazy` must be initialized.
147 #[must_use]
148 #[inline]
149 unsafe fn get_unchecked(&self) -> Option<&T> {
150 unsafe { (*self.value.get()).init.as_ref() }
151 }
152
153 /// Returns a mutable reference to the value,
154 /// or `None` if it has been poisoned.
155 ///
156 /// # Safety
157 ///
158 /// The `Lazy` must be initialized.
159 #[must_use]
160 #[inline]
161 unsafe fn get_unchecked_mut(&mut self) -> Option<&mut T> {
162 unsafe { self.value.get_mut().init.as_mut() }
163 }
164
165 /// Returns a pinned reference to the value,
166 /// or `None` if it has been poisoned.
167 ///
168 /// # Safety
169 ///
170 /// The `Lazy` must be initialized.
171 #[must_use]
172 #[inline]
173 unsafe fn get_unchecked_pin(self: Pin<&Self>) -> Option<Pin<&T>> {
174 unsafe {
175 (*self.value.get())
176 .init
177 .as_ref()
178 .map(|r| Pin::new_unchecked(r))
179 }
180 }
181
182 /// Returns a pinned mutable reference to the value,
183 /// or `None` if it has been poisoned.
184 ///
185 /// # Safety
186 ///
187 /// The `Lazy` must be initialized.
188 #[must_use]
189 #[inline]
190 unsafe fn get_unchecked_pin_mut(self: Pin<&mut Self>) -> Option<Pin<&mut T>> {
191 #[allow(clippy::needless_borrow)]
192 unsafe {
193 self.get_unchecked_mut()
194 .value
195 .get_mut()
196 .init
197 .as_mut()
198 .map(|r| Pin::new_unchecked(r))
199 }
200 }
201
202 /// Gets a reference to the result of this lazy value if it was initialized,
203 /// otherwise returns `None`.
204 #[must_use]
205 #[inline]
206 pub fn get(&self) -> Option<&T> {
207 if self.initialized() {
208 // SAFETY: we just checked that the `Lazy` is initialized
209 unsafe { self.get_unchecked() }
210 } else {
211 None
212 }
213 }
214
215 /// Gets a mutable reference to the result of this lazy value if it was initialized,
216 /// otherwise returns `None`.
217 #[must_use]
218 #[inline]
219 pub fn get_mut(&mut self) -> Option<&mut T> {
220 if self.initialized_mut() {
221 // SAFETY: we just checked that the `Lazy` is initialized
222 unsafe { self.get_unchecked_mut() }
223 } else {
224 None
225 }
226 }
227
228 /// Gets a pinned reference to the result of this lazy value if it was initialized,
229 /// otherwise returns `None`.
230 #[must_use]
231 #[inline]
232 pub fn get_pin(self: Pin<&Self>) -> Option<Pin<&T>> {
233 if self.initialized() {
234 // SAFETY: we just checked that the `Lazy` is initialized
235 unsafe { self.get_unchecked_pin() }
236 } else {
237 None
238 }
239 }
240
241 /// Gets a pinned mutable reference to the result of this lazy value if it was initialized,
242 /// otherwise returns `None`.
243 #[must_use]
244 #[inline]
245 pub fn get_pin_mut(mut self: Pin<&mut Self>) -> Option<Pin<&mut T>> {
246 if self.as_mut().initialized_pin_mut() {
247 // SAFETY: we just checked that the `Lazy` is initialized
248 unsafe { self.get_unchecked_pin_mut() }
249 } else {
250 None
251 }
252 }
253}
254
255impl<T, Fut, F> Lazy<T, Fut, F>
256where
257 Fut: Future<Output = T> + Unpin,
258 F: FnOnce() -> Fut,
259{
260 /// Forces the evaluation of this lazy value and returns a reference to the result.
261 ///
262 /// If the caller of `force` is cancelled, the state of initialization is preserved;
263 /// the next call to `force` starts polling the initializing future again where the last left off.
264 ///
265 /// # Panics
266 ///
267 /// If the initialization function panics, the `Lazy` is poisoned
268 /// and all subsequent calls to this function will panic.
269 #[inline]
270 pub async fn force(&self) -> &T {
271 if !self.initialized() {
272 // SAFETY: the cell is not initialized, so it stores `F` or `Fut`.
273 // And `F` is `Unpin`. So making a pinned reference is safe.
274 unsafe {
275 Pin::new_unchecked(self).initialize().await;
276 }
277 }
278 // SAFETY: we just initialized the `Lazy`
279 (unsafe { self.get_unchecked() })
280 .unwrap_or_else(|| panic!("Lazy instance has previously been poisoned"))
281 }
282
283 /// Forces the evaluation of this lazy value and returns a mutable reference to the result.
284 ///
285 /// # Panics
286 ///
287 /// If the initialization function panics, the `Lazy` is poisoned
288 /// and all subsequent calls to this function will panic.
289 #[inline]
290 pub async fn force_mut(&mut self) -> &mut T {
291 if !self.initialized_mut() {
292 // SAFETY: the cell is not initialized, so it stores `F` or `Fut`.
293 // And `F` is `Unpin`. So making a pinned reference is safe.
294 unsafe {
295 Pin::new_unchecked(&*self).initialize().await;
296 }
297 }
298 // SAFETY: we just initialized the `Lazy`
299 (unsafe { self.get_unchecked_mut() })
300 .unwrap_or_else(|| panic!("Lazy instance has previously been poisoned"))
301 }
302}
303
304impl<T, Fut, F> Lazy<T, Fut, F>
305where
306 Fut: Future<Output = T>,
307 F: FnOnce() -> Fut,
308{
309 /// Initializes the `Lazy`, if it has not yet been.
310 /// Once this has returned, `LazyData` is guaranteed to be in the `value` state.
311 #[cold]
312 async fn initialize(self: Pin<&Self>) {
313 // Here we try to acquire the semaphore permit. Holding the permit
314 // will allow us to set the value of the Lazy, and prevents
315 // other tasks from initializing the Lazy while we are holding
316 // it.
317 match self.semaphore.acquire().await {
318 Ok(permit) => {
319 debug_assert!(!self.initialized());
320
321 enum InitializationState<T> {
322 // The `Lazy` stores the initializing future.
323 Initializing,
324 // The `Lazy` has been fully initialized,
325 // or poisoned if this contains `None`.
326 Initialized(ManuallyDrop<Option<T>>),
327 }
328
329 // If the function panics, we have to set the `Lazy` to poisoned.
330 // So all the initialization work happens on the `Drop` of this struct.
331 struct InitializeOnDrop<'a, 'permit, T, Fut, F> {
332 lazy: Pin<&'a Lazy<T, Fut, F>>,
333 value: InitializationState<T>,
334 permit: ManuallyDrop<SemaphorePermit<'permit>>,
335 }
336
337 impl<T, Fut, F> Drop for InitializeOnDrop<'_, '_, T, Fut, F> {
338 fn drop(&mut self) {
339 match self.value {
340 InitializationState::Initializing => {
341 // Dropped while initializing -
342 // release the permit, give next caller a chance.
343 // At this point, the `Lazy` stores the initializing future.
344 // SAFETY: we are in `drop`, so nobody will access our fields after us.
345 unsafe {
346 drop(ManuallyDrop::take(&mut self.permit));
347 }
348 }
349 InitializationState::Initialized(ref mut value) => {
350 // Write the initialized value to the `Lazy`.
351 // SAFETY: we are in `drop`, so nobody will access our fields after us.
352 unsafe {
353 (*self.lazy.value.get()).init =
354 ManuallyDrop::new(ManuallyDrop::take(value));
355 };
356
357 // FIXME this could be made unsychronized when we have a mutable borrow of the `Lazy`
358 self.lazy.value_set.store(true, Ordering::Release);
359 self.lazy.semaphore.close();
360 }
361 }
362 }
363 }
364
365 // SAFETY: This lazy is uninitialized, so it still stores either the initializing function
366 // or the initializing future.
367 #[allow(clippy::let_and_return)]
368 let uninit_data: &mut ManuallyDrop<LazyUninitData<Fut, F>> = unsafe {
369 let ptr = self.value.get();
370 let mut_ref = &mut (*ptr).uninit;
371 mut_ref
372 };
373
374 // Arm the initialize-on-drop-mechanism.
375 // We start as `poisoned` because if the initialization function panics,
376 // we want the `Lazy` to be poisoned.
377 let mut initialize_on_drop = InitializeOnDrop {
378 lazy: self,
379 value: InitializationState::Initialized(ManuallyDrop::new(None)),
380 permit: ManuallyDrop::new(permit),
381 };
382
383 // We need to hold a raw pointer across an `await`, without impacting auto traits.
384 // Hence this ugliness.
385 struct Wrapper<Fut>(*mut Fut);
386 unsafe impl<Fut> Send for Wrapper<Fut> {}
387 unsafe impl<Fut> Sync for Wrapper<Fut> {}
388
389 let fut_ptr: Wrapper<Fut> = {
390 let mut_ptr: *mut ManuallyDrop<Fut> = match &mut **uninit_data {
391 LazyUninitData::Function(f) => {
392 // SAFETY: The `f` will never be accessed later
393 let f = unsafe { ManuallyDrop::take(f) };
394
395 // Run the initializing function.
396 let fut = f();
397
398 **uninit_data = LazyUninitData::Future(ManuallyDrop::new(fut));
399
400 match &mut **uninit_data {
401 // Someone else already ran the intializing function.
402 // Get a pointer to the future that this `Lazy` is currently storing.
403 LazyUninitData::Future(fut) => fut,
404 _ => unreachable!("We just set this to LazyUninitData::Future"),
405 }
406 }
407 LazyUninitData::Future(fut) => fut,
408 };
409
410 Wrapper(mut_ptr.cast())
411 };
412
413 // SAFETY: `Lazy` futures are structurally pinned.
414 let fut: Pin<&mut Fut> = unsafe { Pin::new_unchecked(&mut *fut_ptr.0) };
415
416 // If we reach this point, the initializing function has run successfully,
417 // and the initializing future is stored in the struct.
418 // Now we disarm the poison mechanism before polling the future.
419 initialize_on_drop.value = InitializationState::Initializing;
420
421 // `await` the initializing future.
422 // If this panics or we are cancelled,
423 // the semaphore permit will be released and the next
424 // caller to `initialize` will keep polling where we left off.
425 let result = fut.await;
426
427 // Set the cell to initialized.
428 initialize_on_drop.value =
429 InitializationState::Initialized(ManuallyDrop::new(Some(result)));
430
431 // Drop the future now that we are done polling it.
432 // SAFETY: there are no accesses to the future after this.
433 unsafe { core::ptr::drop_in_place(fut_ptr.0) }
434
435 drop(initialize_on_drop);
436 }
437 Err(_) => {
438 debug_assert!(self.initialized());
439 }
440 }
441 }
442
443 /// Forces the evaluation of this lazy value and returns a reference to the result.
444 ///
445 /// # Panics
446 ///
447 /// If the initialization function panics, the `Lazy` is poisoned
448 /// and all subsequent calls to this function will panic.
449 #[inline]
450 pub async fn force_pin(self: Pin<&Self>) -> Pin<&T> {
451 if !self.initialized() {
452 self.initialize().await;
453 }
454 // SAFETY: we just initialized the `Lazy`
455 (unsafe { self.get_unchecked_pin() })
456 .unwrap_or_else(|| panic!("Lazy instance has previously been poisoned"))
457 }
458
459 /// Forces the evaluation of this lazy value and returns a mutable reference to the result.
460 ///
461 /// # Panics
462 ///
463 /// If the initialization function panics, the `Lazy` is poisoned
464 /// and all subsequent calls to this function will panic.
465 #[inline]
466 pub async fn force_pin_mut(mut self: Pin<&mut Self>) -> Pin<&mut T> {
467 if !self.as_mut().initialized_pin_mut() {
468 // SAFETY: the cell is not initialized, so it stores `F` or `Fut`.
469 // And `F` is `Unpin`. So making a pinned reference is safe.
470 self.as_ref().initialize().await;
471 }
472 // SAFETY: we just initialized the `Lazy`
473 (unsafe { self.get_unchecked_pin_mut() })
474 .unwrap_or_else(|| panic!("Lazy instance has previously been poisoned"))
475 }
476}
477
478impl<T, Fut, F> Drop for Lazy<T, Fut, F> {
479 #[inline]
480 fn drop(&mut self) {
481 if self.initialized_mut() {
482 // SAFETY: we just checked for the `Lazy` being initialized.
483 // We are inside `drop`, so nobody will access our fields after us.
484 unsafe { ManuallyDrop::drop(&mut self.value.get_mut().init) };
485 } else {
486 // SAFETY: we just check for the `Lazy` being uninitialized.
487 // We hold an `&mut` to this `Lazy`, so nobody else is in the process of initializing it.
488 // We are inside `drop`, so nobody will access our fields after us.
489 unsafe {
490 match &mut *self.value.get_mut().uninit {
491 LazyUninitData::Function(f) => ManuallyDrop::drop(f),
492 LazyUninitData::Future(fut) => ManuallyDrop::drop(fut),
493 }
494 };
495 }
496 }
497}
498
499impl<T: fmt::Debug, Fut, F> fmt::Debug for Lazy<T, Fut, F> {
500 #[inline]
501 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
502 match self.get() {
503 Some(v) => f.debug_tuple("Lazy").field(v).finish(),
504 None => f.write_str("Lazy(Uninit)"),
505 }
506 }
507}
508
509unsafe impl<T: Send, Fut: Send, F: Send> Send for Lazy<T, Fut, F> {}
510
511// We never create a `&F` from a `&Lazy<T, F>` so it is fine
512// to not require a `Sync` bound on `F`.
513// Need `T: Send + Sync` for `Sync` as the thread that initializes
514// the cell could be different from the one that destroys it.
515unsafe impl<T: Send + Sync, Fut: Send, F: Send> Sync for Lazy<T, Fut, F> {}
516
517impl<T: UnwindSafe, Fut: UnwindSafe, F: UnwindSafe> UnwindSafe for Lazy<T, Fut, F> {}
518impl<T: UnwindSafe + RefUnwindSafe, Fut: UnwindSafe, F: UnwindSafe> RefUnwindSafe
519 for Lazy<T, F, Fut>
520{
521}
522
523// F is not structurally pinned.
524impl<T: Unpin, Fut: Unpin, F> Unpin for Lazy<T, Fut, F> {}
525
526#[cfg(feature = "nightly")]
527#[doc(cfg(feature = "nightly"))]
528impl<'a, T, Fut, F> std::future::IntoFuture for &'a Lazy<T, Fut, F>
529where
530 Fut: Future<Output = T> + Unpin,
531 F: FnOnce() -> Fut,
532{
533 type Output = &'a T;
534
535 type IntoFuture = impl Future<Output = Self::Output>;
536
537 #[inline]
538 fn into_future(self) -> Self::IntoFuture {
539 self.force()
540 }
541}
542
543#[cfg(feature = "nightly")]
544#[doc(cfg(feature = "nightly"))]
545impl<'a, T, Fut, F> std::future::IntoFuture for &'a mut Lazy<T, Fut, F>
546where
547 Fut: Future<Output = T> + Unpin,
548 F: FnOnce() -> Fut,
549{
550 type Output = &'a mut T;
551
552 type IntoFuture = impl Future<Output = Self::Output>;
553
554 #[inline]
555 fn into_future(self) -> Self::IntoFuture {
556 self.force_mut()
557 }
558}
559
560#[cfg(feature = "nightly")]
561#[doc(cfg(feature = "nightly"))]
562impl<'a, T, Fut, F> std::future::IntoFuture for Pin<&'a Lazy<T, Fut, F>>
563where
564 Fut: Future<Output = T>,
565 F: FnOnce() -> Fut,
566{
567 type Output = Pin<&'a T>;
568
569 type IntoFuture = impl Future<Output = Self::Output>;
570
571 #[inline]
572 fn into_future(self) -> Self::IntoFuture {
573 self.force_pin()
574 }
575}
576
577#[cfg(feature = "nightly")]
578#[doc(cfg(feature = "nightly"))]
579impl<'a, T, Fut, F> std::future::IntoFuture for Pin<&'a mut Lazy<T, Fut, F>>
580where
581 Fut: Future<Output = T>,
582 F: FnOnce() -> Fut,
583{
584 type Output = Pin<&'a mut T>;
585
586 type IntoFuture = impl Future<Output = Self::Output>;
587
588 #[inline]
589 fn into_future(self) -> Self::IntoFuture {
590 self.force_pin_mut()
591 }
592}