pub struct RwTaskLock<T, E>{ /* private fields */ }Expand description
A one-time async-initialized, lockable value that yields a read guard after initialization.
RwTaskLock<T, E> allows you to wrap a future or ready value so the computation
(e.g., background task, async function) is performed at most once, even if
multiple callers invoke .read() concurrently. After the computation,
the result is cached. If successful, all future .read() calls yield a
read guard on the stored value. If an error occurs, all subsequent calls
return the error (error value must be Clone).
§Example
use tokio::time;
use xet_runtime::utils::{RwTaskLock, RwTaskLockError};
#[tokio::main]
async fn main() -> Result<(), RwTaskLockError> {
let lock = RwTaskLock::from_task(async {
time::sleep(std::time::Duration::from_millis(50)).await;
Ok::<_, RwTaskLockError>(vec![1, 2, 3])
});
let guard = lock.read().await?;
assert_eq!(&*guard, &[1, 2, 3]);
Ok(())
}Implementations§
Source§impl<T, E> RwTaskLock<T, E>
impl<T, E> RwTaskLock<T, E>
Sourcepub fn from_value(val: T) -> Self
pub fn from_value(val: T) -> Self
From a ready value.
Sourcepub async fn read(&self) -> Result<RwTaskLockReadGuard<'_, T, E>, E>
pub async fn read(&self) -> Result<RwTaskLockReadGuard<'_, T, E>, E>
Awaitable read: yields a custom read guard or error.
Sourcepub async fn update<Fut, Updater>(
&self,
updater: Updater,
) -> Result<(), RwTaskLockError>
pub async fn update<Fut, Updater>( &self, updater: Updater, ) -> Result<(), RwTaskLockError>
Update the current value by applying an async function to it, storing the result as the new value.
- If the current value is in the
Readystate, the function is immediately scheduled as a background task with the current value, and the state becomesPendinguntil completion. - If the value is in the
Pendingstate, this chains the update: when the background task completes, the updater will be called on the resulting value. - If the value is in the
Errorstate, returns an error and does nothing.
Returns Ok(()) if the update is scheduled. Errors if the value is already in an error state.
§Example: Chaining updates
use tokio::time;
use xet_runtime::utils::{RwTaskLock, RwTaskLockError};
#[tokio::main]
async fn main() -> Result<(), RwTaskLockError> {
let lock = RwTaskLock::from_value(10);
lock.update(|v| async move { Ok::<_, RwTaskLockError>(v * 2) }).await?;
assert_eq!(*lock.read().await?, 20);
lock.update(|v| async move { Ok::<_, RwTaskLockError>(v + 5) }).await?;
assert_eq!(*lock.read().await?, 25);
Ok(())
}§Example: Chained with pending state
use std::sync::Arc;
use tokio::time;
use xet_runtime::utils::{RwTaskLock, RwTaskLockError};
#[tokio::main]
async fn main() -> Result<(), RwTaskLockError> {
let lock = Arc::new(RwTaskLock::from_task(async {
time::sleep(std::time::Duration::from_millis(10)).await;
Ok::<_, RwTaskLockError>(10)
}));
let lock2 = lock.clone();
// Chain update while value is still pending
lock2.update(|v| async move { Ok::<_, RwTaskLockError>(v + 10) }).await?;
assert_eq!(*lock.read().await?, 20);
Ok(())
}