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>
impl<T> OnceCell<T>
sourcepub const fn new() -> Self
pub const fn new() -> Self
Create a new, uninitialized OnceCell
.
§Example
use async_lock::OnceCell;
let cell = OnceCell::new();
sourcepub fn is_initialized(&self) -> bool
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());
sourcepub fn get(&self) -> Option<&T>
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));
sourcepub fn get_mut(&mut self) -> Option<&mut T>
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));
sourcepub fn take(&mut self) -> Option<T>
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());
sourcepub fn into_inner(self) -> Option<T>
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));
sourcepub async fn wait(&self) -> &T
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);
sourcepub fn wait_blocking(&self) -> &T
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);
sourcepub async fn get_or_try_init<E, Fut: Future<Output = Result<T, E>>>(
&self,
closure: impl FnOnce() -> Fut,
) -> Result<&T, E>
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);
sourcepub fn get_or_try_init_blocking<E>(
&self,
closure: impl FnOnce() -> Result<T, E>,
) -> Result<&T, E>
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);
sourcepub async fn get_or_init<Fut: Future<Output = T>>(
&self,
closure: impl FnOnce() -> Fut,
) -> &T
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);
sourcepub fn get_or_init_blocking(&self, closure: impl FnOnce() -> T + Unpin) -> &T
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);
sourcepub async fn set(&self, value: T) -> Result<&T, T>
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));
sourcepub fn set_blocking(&self, value: T) -> Result<&T, T>
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));
sourcepub unsafe fn get_unchecked(&self) -> &T
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);