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}