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§

source§

impl<T> OnceCell<T>

source

pub const fn new() -> Self

Create a new, uninitialized OnceCell.

Example
use async_lock::OnceCell;

let cell = OnceCell::new();
source

pub fn is_initialized(&self) -> bool

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());
source

pub fn get(&self) -> Option<&T>

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));
source

pub fn get_mut(&mut self) -> Option<&mut T>

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));
source

pub fn take(&mut self) -> Option<T>

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());
source

pub fn into_inner(self) -> Option<T>

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));
source

pub async fn wait(&self) -> &T

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);
source

pub fn wait_blocking(&self) -> &T

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);
source

pub async fn get_or_try_init<E, Fut: Future<Output = Result<T, E>>>( &self, closure: impl FnOnce() -> Fut ) -> Result<&T, E>

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);
source

pub fn get_or_try_init_blocking<E>( &self, closure: impl FnOnce() -> Result<T, E> ) -> Result<&T, E>

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);
source

pub async fn get_or_init<Fut: Future<Output = T>>( &self, closure: impl FnOnce() -> Fut ) -> &T

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);
source

pub fn get_or_init_blocking(&self, closure: impl FnOnce() -> T + Unpin) -> &T

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);
source

pub async fn set(&self, value: T) -> Result<&T, T>

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));
source

pub fn set_blocking(&self, value: T) -> Result<&T, T>

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));
source

pub unsafe fn get_unchecked(&self) -> &T

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§

source§

impl<T: Debug> Debug for OnceCell<T>

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl<T> Default for OnceCell<T>

source§

fn default() -> Self

Returns the “default value” for a type. Read more
source§

impl<T> Drop for OnceCell<T>

source§

fn drop(&mut self)

Executes the destructor for this type. Read more
source§

impl<T> From<T> for OnceCell<T>

source§

fn from(value: T) -> Self

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));
source§

impl<T: Send> Send for OnceCell<T>

source§

impl<T: Send + Sync> Sync for OnceCell<T>

Auto Trait Implementations§

§

impl<T> !RefUnwindSafe for OnceCell<T>

§

impl<T> Unpin for OnceCell<T>
where T: Unpin,

§

impl<T> UnwindSafe for OnceCell<T>
where T: UnwindSafe,

Blanket Implementations§

source§

impl<T> Any for T
where T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<!> for T

source§

fn from(t: !) -> T

Converts to this type from the input type.
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

source§

impl<T, U> Into<U> for T
where U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

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

source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.