Struct Deferred

Source
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>
where T: Send + Sync + 'static,

Source

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

pub fn start<F, Fut>(computation: F) -> Self
where F: FnOnce() -> Fut + Send + 'static, Fut: Future<Output = T> + Send + 'static,

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

pub fn start_with_callback<F, C, Fut>(computation: F, callback: C) -> Self
where F: FnOnce() -> Fut + Send + 'static, C: FnOnce() + Send + 'static, Fut: Future<Output = T> + Send + 'static,

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!")
);
Source

pub fn begin<F, Fut>(&mut self, computation: F) -> bool
where F: FnOnce() -> Fut + Send + 'static, Fut: Future<Output = T> + Send + 'static,

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
 
Source

pub fn begin_with_callback<F, C, Fut>( &mut self, computation: F, callback: C, ) -> bool
where F: FnOnce() -> Fut + Send + 'static, C: FnOnce() + Send + 'static, Fut: Future<Output = T> + Send + 'static,

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

pub fn state(&self) -> State

Returns the current state of the task.

§Returns
  • State::NotInitialized - The task hasn’t been started yet
  • State::Pending - The task is currently running
  • State::Completed - The task completed successfully or the callback panicked
  • State::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));
Source

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 yet
  • State::Pending - The task is currently running
  • State::Completed - The task completed successfully
  • State::TaskPanicked - The task panicked during execution
  • State::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(_)));
Source

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);
}
Source

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

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

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

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

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

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 running
Source

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

Trait Implementations§

Source§

impl<T: Debug> Debug for Deferred<T>

Source§

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

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

impl<T> Default for Deferred<T>
where T: Send + Sync + 'static,

Source§

fn default() -> Self

Creates a new empty Deferred instance.

Equivalent to Deferred::new().

Auto Trait Implementations§

§

impl<T> Freeze for Deferred<T>

§

impl<T> !RefUnwindSafe for Deferred<T>

§

impl<T> Send for Deferred<T>
where T: Sync + Send,

§

impl<T> Sync for Deferred<T>
where T: Sync + Send,

§

impl<T> Unpin for Deferred<T>

§

impl<T> !UnwindSafe for Deferred<T>

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<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>,

Source§

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>,

Source§

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.