Struct async_lock::OnceCell

source ·
pub struct OnceCell<T> { /* private fields */ }
Expand description

A memory location that can be written to at most once.

A OnceCell can be used to store a single value, and only once. However, once the value is stored, it can be accessed directly through a reference instead of needing an RAII guard like Mutex or RwLock.

Examples

This structure is useful for a variety of patterns, most notably for one-time initialization.

use async_lock::OnceCell;


async fn very_expensive_initialization() -> Foobar {
    // Imagine this is very expensive to initialize,
    // for instance, it requires a network request or
    // a database call.
}

struct LazyFoobar {
    inner: OnceCell<Foobar>,
}

impl LazyFoobar {
    fn new() -> Self {
        Self {
            inner: OnceCell::new(),
        }
    }

    async fn load(&self) -> &Foobar {
        self.inner.get_or_init(|| async {
            very_expensive_initialization().await
        }).await
    }
}

Implementations§

Create a new, uninitialized OnceCell.

Example
use async_lock::OnceCell;

let cell = OnceCell::new();

Tell whether or not the cell is initialized.

This may not always be accurate. For instance, it is possible for another thread to initialize the cell between the time when this function is called and the time when the result is actually used.

Example
use async_lock::OnceCell;

let cell = OnceCell::new();
assert!(!cell.is_initialized());
cell.set(1).await;
assert!(cell.is_initialized());

Get a reference to the inner value, or None if the value is not yet initialized.

Example
use async_lock::OnceCell;

let cell = OnceCell::new();
assert!(cell.get().is_none());
cell.set(1).await;
assert_eq!(cell.get(), Some(&1));

Get a mutable reference to the inner value, or None if the value is not yet initialized.

This function is useful for initializing the value inside the cell when we still have a mutable reference to the cell.

Example
use async_lock::OnceCell;

let mut cell = OnceCell::new();
assert!(cell.get_mut().is_none());
cell.set(1).await;
assert_eq!(cell.get_mut(), Some(&mut 1));
*cell.get_mut().unwrap() = 2;
assert_eq!(cell.get(), Some(&2));

Take the value out of this OnceCell, moving it back to the uninitialized state.

Example
use async_lock::OnceCell;

let mut cell = OnceCell::new();
cell.set(1).await;
assert_eq!(cell.take(), Some(1));
assert!(!cell.is_initialized());

Convert this OnceCell into the inner value, if it is initialized.

Example
use async_lock::OnceCell;

let cell = OnceCell::new();
cell.set(1).await;
assert_eq!(cell.into_inner(), Some(1));

Wait for the cell to be initialized, and then return a reference to the inner value.

Example
use async_lock::OnceCell;
use std::sync::Arc;
use std::time::Duration;
use std::thread::{sleep, spawn};

let cell = Arc::new(OnceCell::new());
let cell2 = cell.clone();

spawn(move || {
   sleep(Duration::from_millis(5));
   cell2.set_blocking(1);
});

assert_eq!(cell.wait().await, &1);

Wait for the cell to be initialized, and then return a reference to the inner value.

Blocking

In contrast to the wait method, this method blocks the current thread of execution instead of awaiting.

This method should not be used in an asynchronous context. It is intended to be used such that a OnceCell can be used in both asynchronous and synchronous contexts. Calling this method in an asynchronous context may result in deadlocks.

Example
use async_lock::OnceCell;
use std::sync::Arc;
use std::time::Duration;
use std::thread::{sleep, spawn};

let cell = Arc::new(OnceCell::new());
let cell2 = cell.clone();

spawn(move || {
   sleep(Duration::from_millis(5));
   cell2.set_blocking(1);
});

assert_eq!(cell.wait_blocking(), &1);

Either get the value or initialize it with the given closure.

The cell will not be initialized if the closure returns an error.

Example
use async_lock::OnceCell;

let cell = OnceCell::new();

let result = cell.get_or_try_init(|| async { Err(()) }).await;
assert!(result.is_err());

let result = cell.get_or_try_init(|| async { Ok(1) }).await;
assert_eq!(result.unwrap(), &1);

let result = cell.get_or_try_init(|| async { Err(()) }).await;

assert_eq!(result.unwrap(), &1);

Either get the value or initialize it with the given closure.

The cell will not be initialized if the closure returns an error.

Blocking

In contrast to the get_or_try_init method, this method blocks the current thread of execution instead of awaiting.

This method should not be used in an asynchronous context. It is intended to be used such that a OnceCell can be used in both asynchronous and synchronous contexts. Calling this method in an asynchronous context may result in deadlocks.

Example
use async_lock::OnceCell;

let cell = OnceCell::new();

let result = cell.get_or_try_init_blocking(|| Err(()));
assert!(result.is_err());

let result = cell.get_or_try_init_blocking(|| Ok(1));
assert_eq!(result.unwrap(), &1);

let result = cell.get_or_try_init_blocking(|| Err(()));

assert_eq!(result.unwrap(), &1);

Either get the value or initialize it with the given closure.

Many tasks may call this function, but the value will only be set once and only one closure will be invoked.

Example
use async_lock::OnceCell;

let cell = OnceCell::new();
assert_eq!(cell.get_or_init(|| async { 1 }).await, &1);
assert_eq!(cell.get_or_init(|| async { 2 }).await, &1);

Either get the value or initialize it with the given closure.

Many tasks may call this function, but the value will only be set once and only one closure will be invoked.

Blocking

In contrast to the get_or_init method, this method blocks the current thread of execution instead of awaiting.

This method should not be used in an asynchronous context. It is intended to be used such that a OnceCell can be used in both asynchronous and synchronous contexts. Calling this method in an asynchronous context may result in deadlocks.

Example
use async_lock::OnceCell;

let cell = OnceCell::new();
assert_eq!(cell.get_or_init_blocking(|| 1), &1);
assert_eq!(cell.get_or_init_blocking(|| 2), &1);

Try to set the value of the cell.

If the cell is already initialized, this method returns the original value back.

Example
use async_lock::OnceCell;

let cell = OnceCell::new();

assert_eq!(cell.set(1).await, Ok(&1));
assert_eq!(cell.get(), Some(&1));
assert_eq!(cell.set(2).await, Err(2));

Try to set the value of the cell.

If the cell is already initialized, this method returns the original value back.

Blocking

In contrast to the set method, this method blocks the current thread of execution instead of awaiting.

This method should not be used in an asynchronous context. It is intended to be used such that a OnceCell can be used in both asynchronous and synchronous contexts. Calling this method in an asynchronous context may result in deadlocks.

Example
use async_lock::OnceCell;

let cell = OnceCell::new();

assert_eq!(cell.set_blocking(1), Ok(&1));
assert_eq!(cell.get(), Some(&1));
assert_eq!(cell.set_blocking(2), Err(2));

Get a reference to the inner value.

Safety

The caller must ensure that the cell is initialized.

Example
use async_lock::OnceCell;

let cell = OnceCell::new();
cell.set(1).await;

// SAFETY: We know that the value is initialized, so it is safe to
// read it.
assert_eq!(unsafe { cell.get_unchecked() }, &1);

Trait Implementations§

Formats the value using the given formatter. Read more
Executes the destructor for this type. Read more

Create a new, initialized OnceCell from an existing value.

Example
use async_lock::OnceCell;

let cell = OnceCell::from(42);
assert_eq!(cell.get(), Some(&42));

Auto Trait Implementations§

Blanket Implementations§

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Converts to this type from the input type.

Returns the argument unchanged.

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.