pub struct Deferred<T> { /* private fields */ }Expand description
A handle to an asynchronous computation that allows for deferred result retrieval.
This struct supports the “fire-and-forget” pattern with the ability to later query the result or detect if the task panicked. It’s useful when you want to start a computation but don’t need the result immediately.
§Examples
use async_deferred::Deferred;
// Start a computation immediately
let mut deferred = Deferred::start(|| async {
tokio::time::sleep(tokio::time::Duration::from_millis(10)).await;
42
});
// Later, get the result
let result = deferred.join().await.try_get();
assert_eq!(result, Some(&42));// Create and start manually
use async_deferred::Deferred;
let mut deferred = Deferred::new();
deferred.begin(|| async { "Hello, World!" });
// Check if ready without blocking (might not be ready yet)
match deferred.try_get() {
Some(result) => println!("Result: {}", result),
None => println!("Not ready yet"),
}§Thread Safety
Deferred<T> is Send and Sync when T is Send and Sync, making it safe to
share across threads and async tasks.
§Memory Management
Internally, the task runs on Tokio’s async runtime, and the result is stored in a OnceCell.
The computation runs independently and the result is cached until retrieved via take() or
the Deferred is dropped.
Implementations§
Source§impl<T> Deferred<T>
impl<T> Deferred<T>
Sourcepub fn new() -> Self
pub fn new() -> Self
Creates a new empty Deferred instance.
The task must be started manually using begin or begin_with_callback.
§Examples
use async_deferred::Deferred;
let mut deferred = Deferred::new();
assert!(deferred.is_not_initialized());
deferred.begin(|| async { 42 });
assert!(!deferred.is_not_initialized());Sourcepub fn start<F, Fut>(computation: F) -> Self
pub fn start<F, Fut>(computation: F) -> Self
Starts a new asynchronous task and returns a Deferred handle.
This is a convenient way to construct and start the deferred task in one step.
§Arguments
computation- An async function or closure that returns the result of the task.
§Examples
use async_deferred::Deferred;
let deferred = Deferred::start(|| async {
// Some computation
42
});
// Task is already running
assert!(deferred.is_pending() || deferred.is_ready());Sourcepub fn start_with_callback<F, C, Fut>(computation: F, callback: C) -> Self
pub fn start_with_callback<F, C, Fut>(computation: F, callback: C) -> Self
Starts a new asynchronous task with a callback that is called once the task completes.
The callback is executed after the computation finishes, regardless of whether it succeeded or panicked. This is useful for logging, cleanup, or notifications.
§Arguments
computation- An async function or closure that returns the result of the task.callback- A closure that will be run after the task completes.
§Examples
use async_deferred::Deferred;
let deferred = Deferred::start_with_callback(
|| async { 42 },
|| println!("Computation finished!")
);Sourcepub fn begin<F, Fut>(&mut self, computation: F) -> bool
pub fn begin<F, Fut>(&mut self, computation: F) -> bool
Begins execution of the deferred task.
Returns true if the task was successfully started, or false if it has already
been started or completed.
§Arguments
computation- An async function or closure that returns the result of the task.
§Examples
use async_deferred::Deferred;
let mut deferred = Deferred::new();
assert!(deferred.begin(|| async { 42 })); // Started successfully
assert!(!deferred.begin(|| async { 24 })); // Already started, returns false
Sourcepub fn begin_with_callback<F, C, Fut>(
&mut self,
computation: F,
callback: C,
) -> bool
pub fn begin_with_callback<F, C, Fut>( &mut self, computation: F, callback: C, ) -> bool
Begins execution of the deferred task and executes a callback after completion.
Returns true if the task was successfully started, or false if it has already
been started or completed.
§Arguments
computation- An async function or closure that returns the result of the task.callback- A closure that will be run after the task completes.
§Examples
use async_deferred::Deferred;
let mut deferred = Deferred::new();
let started = deferred.begin_with_callback(
|| async { 42 },
|| println!("Task completed!")
);
assert!(started);Sourcepub fn state(&self) -> State
pub fn state(&self) -> State
Returns the current state of the task.
§Returns
State::NotInitialized- The task hasn’t been started yetState::Pending- The task is currently runningState::Completed- The task completed successfully or the callback panickedState::TaskPanicked- The task panicked during execution
state only detects if the task has panicked and not the callback.
If you need this information, use join or state_async.
§Examples
use async_deferred::{Deferred, State};
let mut deferred: Deferred<u32> = Deferred::new();
assert!(matches!(deferred.state(), State::NotInitialized));
deferred.begin(|| async {
tokio::time::sleep(tokio::time::Duration::from_millis(10)).await;
42
});
assert!(matches!(deferred.state(), State::Pending));
tokio::time::sleep(tokio::time::Duration::from_millis(100)).await;
assert!(matches!(deferred.state(), State::Completed));If panicked due to the callback, state will return State::Completed.
use async_deferred::{Deferred, State};
let mut deferred: Deferred<u32> = Deferred::start_with_callback(
|| async {42},
|| {panic!("the callback panicked");},
);
tokio::time::sleep(tokio::time::Duration::from_millis(10)).await;
// state only detects if the task has panicked and not the callback
assert!(matches!(deferred.state(), State::Completed));Sourcepub async fn state_async(&mut self) -> State
pub async fn state_async(&mut self) -> State
Returns the current state of the task. This method is able to correctly
diagnose when a given callback panics, as opposed to state.
Though asynchronous, it will not block until the task completes.
§Returns
State::NotInitialized- The task hasn’t been started yetState::Pending- The task is currently runningState::Completed- The task completed successfullyState::TaskPanicked- The task panicked during executionState::CallbackPanicked- The callback panicked during execution
§Examples
use async_deferred::{Deferred, State};
let mut deferred: Deferred<u32> = Deferred::new();
assert!(matches!(deferred.state_async().await, State::NotInitialized));
deferred.begin(|| async {
tokio::time::sleep(tokio::time::Duration::from_millis(10)).await;
42
});
// The task is not done yet
assert!(matches!(deferred.state_async().await, State::Pending));
tokio::time::sleep(tokio::time::Duration::from_millis(100)).await;
// The task is completed
assert!(matches!(deferred.state_async().await, State::Completed));use async_deferred::{Deferred, State};
let mut deferred: Deferred<u32> = Deferred::start_with_callback(
|| async { panic!("the task panicked"); 42 },
|| { panic!("callback will not be called since the task panicked"); },
);
tokio::time::sleep(tokio::time::Duration::from_millis(10)).await;
assert!(matches!(deferred.state_async().await, State::TaskPanicked(_)));use async_deferred::{Deferred, State};
let mut deferred: Deferred<u32> = Deferred::start_with_callback(
|| async { 42 },
|| { panic!("the callback panicked"); },
);
tokio::time::sleep(tokio::time::Duration::from_millis(10)).await;
assert!(matches!(deferred.state_async().await, State::CallbackPanicked(_)));Sourcepub fn try_get(&self) -> Option<&T>
pub fn try_get(&self) -> Option<&T>
Attempts to retrieve the result of the computation if available.
Returns Some(&T) if the task has completed successfully, or None if the task
is still pending, panicked, or not started.
This is a non-blocking operation that returns immediately.
§Examples
use async_deferred::Deferred;
let deferred = Deferred::start(|| async { 42 });
// Might return None if task hasn't finished yet
if let Some(result) = deferred.try_get() {
println!("Result: {}", result);
}Sourcepub async fn join(&mut self) -> &Self
pub async fn join(&mut self) -> &Self
Waits for the task to complete and returns a reference to self.
If the task is still pending, this will await its completion (either success or panic). If the task has already completed or panicked, this returns immediately.
This method allows for method chaining: deferred.join().await.try_get().
§Examples
use async_deferred::Deferred;
let mut deferred = Deferred::start(|| async {
tokio::time::sleep(tokio::time::Duration::from_millis(100)).await;
42
});
// Wait for completion and get result
let result = deferred.join().await.try_get();
assert_eq!(result, Some(&42));Sourcepub fn cancel(&mut self) -> bool
pub fn cancel(&mut self) -> bool
Cancels the current task if it’s pending.
If the task is not pending (completed, panicked, or not initialized),
this method does nothing and returns false. Returns true if the
task was successfully cancelled.
After cancellation, the Deferred returns to the NotInitialized state
and can be reused with a new task via begin() or begin_with_callback().
§Returns
trueif a pending task was cancelledfalseif there was no pending task to cancel
§Examples
use async_deferred::{Deferred, State};
let mut deferred = Deferred::start(|| async {
tokio::time::sleep(tokio::time::Duration::from_secs(10)).await;
42
});
let was_cancelled = deferred.cancel();
assert!(was_cancelled);
assert_eq!(deferred.state(), State::NotInitialized);
// Can reuse the deferred after cancellation
deferred.begin(|| async { 100 });
assert!(deferred.is_pending());use async_deferred::{Deferred, State};
// Task completes quickly
let mut deferred = Deferred::start(|| async { 42 });
tokio::time::sleep(tokio::time::Duration::from_millis(100)).await;
// Try to cancel after completion - does nothing
let was_cancelled = deferred.cancel();
assert!(!was_cancelled);
assert_eq!(deferred.state(), State::Completed);
assert_eq!(deferred.take(), Some(42));use async_deferred::{Deferred, State};
// Not initialized yet
let mut deferred: Deferred<i32> = Deferred::new();
// Try to cancel uninitialized task - does nothing
let was_cancelled = deferred.cancel();
assert!(!was_cancelled);
assert_eq!(deferred.state(), State::NotInitialized);Sourcepub fn take(&mut self) -> Option<T>
pub fn take(&mut self) -> Option<T>
Attempts to take ownership of the computed value.
Returns Some(T) if the task has completed successfully, consuming the stored result.
Returns None if the task is still pending, panicked, or not started.
After calling this method successfully, subsequent calls will return None since
the value has been moved out.
§Examples
use async_deferred::Deferred;
let mut deferred = Deferred::start(|| async { vec![1, 2, 3] });
// Wait for completion
deferred.join().await;
// Take ownership of the result
let result = deferred.take();
assert_eq!(result, Some(vec![1, 2, 3]));
// Subsequent calls return None
assert_eq!(deferred.take(), None);take will not consume if it is still pending
use async_deferred::Deferred;
let mut deferred = Deferred::start(|| async {
tokio::time::sleep(tokio::time::Duration::from_millis(10)).await;
42
});
// If still pending, doesn't consume it
assert_eq!(deferred.take(), None);
tokio::time::sleep(tokio::time::Duration::from_millis(100)).await;
assert!(matches!(deferred.try_get(), Some(42)));Sourcepub fn has_task_panicked(&self) -> bool
pub fn has_task_panicked(&self) -> bool
Returns true if the task panicked during execution.
A task is considered panicked if it was started but the JoinHandle indicates
it finished without storing a result in the OnceCell.
§Examples
use async_deferred::Deferred;
let mut deferred = Deferred::start(|| async {
panic!("Something went wrong!");
});
tokio::time::sleep(tokio::time::Duration::from_millis(100)).await;
assert!(deferred.has_task_panicked());Sourcepub fn is_ready(&self) -> bool
pub fn is_ready(&self) -> bool
Returns true if the data is available.
§Examples
use async_deferred::Deferred;
let mut deferred = Deferred::start(|| async {
tokio::time::sleep(tokio::time::Duration::from_millis(100)).await;
42
});
// Initially not ready
assert!(!deferred.is_ready());
deferred.join().await;
assert!(deferred.is_ready());Sourcepub fn is_complete(&self) -> bool
pub fn is_complete(&self) -> bool
Returns true if the task has completed successfully.
This means the computation finished without panicking and a result is available
via try_get or take.
§Examples
use async_deferred::Deferred;
let mut deferred = Deferred::start(|| async {
tokio::time::sleep(tokio::time::Duration::from_millis(100)).await;
42
});
// Initially not ready
assert!(!deferred.is_complete());
deferred.join().await;
println!("{:?}", deferred.state());
assert!(deferred.is_complete());Sourcepub fn is_pending(&self) -> bool
pub fn is_pending(&self) -> bool
Returns true if the task is currently running.
A task is pending if it has been started but hasn’t completed or panicked yet.
§Examples
use async_deferred::Deferred;
let deferred = Deferred::start(|| async {
tokio::time::sleep(tokio::time::Duration::from_millis(100)).await;
42
});
assert!(deferred.is_pending()); // Task is runningSourcepub fn is_not_initialized(&self) -> bool
pub fn is_not_initialized(&self) -> bool
Returns true if the task hasn’t been initialized yet.
This is the initial state of a Deferred created with new.
§Examples
use async_deferred::Deferred;
let deferred: Deferred<i32> = Deferred::new();
assert!(deferred.is_not_initialized());
let started_deferred = Deferred::start(|| async { 42 });
assert!(!started_deferred.is_not_initialized());