#lazy-evaluation #async #static

no-std async-once-cell

Async single assignment cells and lazy values

13 releases

0.5.3 Jul 9, 2023
0.4.4 Feb 22, 2023
0.4.2 Jun 27, 2022
0.3.0 Aug 11, 2021

#93 in Rust patterns

Download history 17096/week @ 2023-12-12 18029/week @ 2023-12-19 12261/week @ 2023-12-26 23702/week @ 2024-01-02 22667/week @ 2024-01-09 23264/week @ 2024-01-16 26928/week @ 2024-01-23 23085/week @ 2024-01-30 24266/week @ 2024-02-06 24658/week @ 2024-02-13 24452/week @ 2024-02-20 27068/week @ 2024-02-27 26738/week @ 2024-03-05 27898/week @ 2024-03-12 31930/week @ 2024-03-19 25615/week @ 2024-03-26

116,454 downloads per month
Used in 92 crates (23 directly)


788 lines

Crates.io API reference


async_once_cell is a version of once_cell that adds support for async initialization of cells. The short version of the API is:

impl OnceCell<T> {
    fn new() -> OnceCell<T>;
    fn get(&self) -> Option<&T>;
    async fn get_or_init(&self, init: impl Future<Output=T>) -> &T;

More patterns and use-cases are in the docs!


A collection of lazy initialized values that are created by Futures.

[OnceCell]'s API is similar to the once_cell crate, std::cell::OnceCell, or std::sync::OnceLock. It provides an async version of a cell that can only be initialized once, permitting tasks to wait on the initialization if it is already running instead of racing multiple initialization tasks.

Unlike threads, tasks can be cancelled at any point where they block. [OnceCell] deals with this by allowing another initializer to run if the task currently initializing the cell is dropped. This also allows for fallible initialization using OnceCell::get_or_try_init and for the initializing Future to contain borrows or use references to thread-local data.

[Lazy] takes the opposite approach: it wraps a single Future which is cooperatively run to completion by any polling task. This requires that the initialization function be independent of the calling context, but will never restart an initializing function just because the surrounding task was cancelled. Using a trait object (Pin<Box<dyn Future>>) for the future may simplify using this type in data structures.


Both cells use two usizes to store state and do not retain any allocations after initialization is complete. Allocations are only required if there is contention.

Accessing an already-initialized cell is as cheap as possible: only one atomic load with Acquire ordering.


The critical-section feature

If this feature is enabled, the critical-section crate is used instead of an std mutex. You must depend on that crate and select a locking implementation; see its documentation for details.

The std feature

This is currently a no-op, but might in the future be used to expose APIs that depends on types only in std. It does not control the locking implementation.