Skip to main content

Task

Struct Task 

Source
pub struct Task<F> { /* private fields */ }
Expand description

A scheduled asynchronous task that manages execution, dependencies, error handling, and lifecycle state.

The task consists of an execution unit that holds the main future. It also manages dependencies, including direct and detached ones, and determines how they are polled. All dependencies (if any) must complete before this task executes. Direct dependencies may be polled:

  • Concurrently (cooperatively interleaved)
  • Synchronously (one-by-one in sequence)
  • Detached (spawned in parallel threads)

Cloures can be also added as detached dependencies in separate queue which executes them in parallel. Error handling behavior can be defined to control whether dependencies should stop execution based on the returned value.

Implementations§

Source§

impl<F> Task<F>
where F: Future,

Source

pub fn new(future: F) -> Self

Creates a new task with the given future.

The provided future represents the main task to be executed. Dependencies can be added using depends_on or depends_on_if, and they will be polled according to the specified polling strategy.

If the future F returns a value, that value must implement the Default trait, as it will be used as the default value for the task if it is canceled.

The task itself does not start running immediately; it must be .awaited or run with Scheduler to execute.

Source

pub fn depends_on<R>( &mut self, future: impl Future<Output = R> + Send + Sync + 'static, ) -> &mut Self

Adds a dependency that must complete before this task continues execution.

The provided future is added as a dependency and will be polled according to the task’s polling strategy. Dependencies can be polled sequentially, concurrently, or in a detached manner (executed on a separate thread from a thread pool).

By default, dependencies are polled concurrently.

  • If the polling strategy is sequential or concurrent, the dependency will be polled in the same executor context.
  • If the polling strategy is detached, the dependency will be polled in a separate thread pool, so it must avoid using executor-specific functions, like tokio::time::sleep(). In this case dependencies should only use general-purpose futures that are agnostic to any particular runtime or executor.

This method ensures that the given future will be polled as part of the dependency execution flow but does not affect whether subsequent dependencies or the main task should execute.

Source

pub fn depends_on_if<R>( &mut self, future: impl Future<Output = R> + Send + Sync + 'static, should_continue: impl FnOnce(R) -> bool + Send + Sync + 'static, ) -> &mut Self

Adds a conditional dependency that may prevent the main task from running and cancel certain dependencies.

This method behaves the same as depends_on but with the added feature that execution is conditional based on the result of the given future.

The provided future is added as a dependency and will be polled according to the task’s polling strategy (sequential, concurrent, or detached). Once the future completes, its result is passed to the should_continue closure.

  • If should_continue returns true, execution of other dependencies continues as usual, and the main task will run.
  • If should_continue returns false, the main task will not run, and it will instead return its default value.
  • Other dependencies may or may not start execution, depending on the polling strategy:
    • If the polling strategy is sequential, no further dependencies will run.
    • If the polling strategy is concurrent or detached, some dependencies may start execution before cancellation occurs.
    • Any dependencies that have already started will be canceled. Dependencies that have not started will not run.

This method is useful for conditionally stopping execution based on the result of a dependency.

§Example
task
    // If `dependency_2` fails will be canceled if still running.
    .depends_on(dependency_1)
    .depends_on_if(dependency_2, |result| result > 0)
    // If `dependency_2` fails, will be canceled if running or not run at all.
    .depends_on(dependency_3);

task.await; // If `dependency_2` fails, the main task will not run.
Source

pub fn depends_on_detached<R>( &mut self, task_fn: impl FnOnce() -> R + Send + Sync + 'static, ) -> &mut Self

Adds a dependency that runs in a separate thread from the thread pool.

Unlike depends_on, which polls futures asynchronously, this method takes a synchronous closure (FnOnce) and executes it in a dedicated thread from the thread pool.

This is useful for integrating CPU-bound or blocking operations that should not be executed within an async context. Each provided closure runs fully in its own thread, independent of the task’s main execution flow.

Threads for these dependencies are managed by a thread pool, ensuring efficient resource utilization.
The main task will not execute until all detached closures have completed.

§Example
task.depends_on_detached(|| {
    // Perform some blocking computation.
    std::thread::sleep(std::time::Duration::from_secs(1));
});

task.await; // Main task runs only after all detached closures finish.
Source

pub fn depends_on_detached_if<R: 'static>( &mut self, task_fn: impl FnOnce() -> R + Send + Sync + 'static, should_continue: impl FnOnce(R) -> bool + Send + Sync + 'static, ) -> &mut Self

Adds a dependency that runs in a separate thread from the thread pool, with a condition to determine task continuation.

Similar to depends_on_detached, this method executes a synchronous closure (FnOnce) in a dedicated thread from the thread pool. However, it also takes a should_continue closure, which receives the result of the dependency and determines whether execution should proceed.

If should_continue returns false, any already-running detached dependencies will be canceled,
and dependencies that have not yet started will not run. The main task will not execute.

Threads for these dependencies are managed by a thread pool, ensuring efficient resource utilization.

Note: This is separate from the detached polling strategy used for async dependencies.

§Example
task
    .depends_on_detached_if(
        || {
            // Perform some blocking computation.
            42
        },
        // If `result <= 0`, running dependencies will be canceled, pending ones
        // won't start, and the main task won't run.
        |result| result > 0,
    )
    .depends_on_detached(|| println!("Another detached task"));

task.await; // Main task runs only if `should_continue` returned true.
Source

pub fn get_handle(&self) -> TaskHandle

Returns a handle for canceling the task and its dependencies.
The returned TaskHandle can be used to prevent the task from starting or to stop it if already running.
Any pending dependencies will not start, while running dependencies will be stopped.

Source

pub fn sequential(&mut self) -> &mut Self

Sets the polling strategy to sequential.
Dependencies will be polled one at a time in the order they were added, ensuring that each dependency completes before the next one starts.

Source

pub fn detached(&mut self) -> &mut Self

Sets the polling strategy to detached.
Dependencies will be polled in separate threads from the thread pool, allowing them to run independently. This means dependencies will execute in parallel without blocking the main task.
Note: When using this strategy, dependencies must not use executor-specific code (e.g., tokio::time::sleep()), as this will cause a panic.

Source

pub fn concurrent(&mut self) -> &mut Self

Sets the polling strategy to concurrent.
Dependencies will be polled simultaneously, allowing them to make progress independently. This strategy maximizes concurrency and is the default if no other strategy is set.

Trait Implementations§

Source§

impl<F> Future for Task<F>
where F: Future<Output: Default>,

Source§

type Output = <F as Future>::Output

The type of value produced on completion.
Source§

fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output>

Attempts to resolve the future to a final value, registering the current task for wakeup if the value is not yet available. Read more

Auto Trait Implementations§

§

impl<F> !RefUnwindSafe for Task<F>

§

impl<F> !UnwindSafe for Task<F>

§

impl<F> Freeze for Task<F>
where Pin<Box<F>>: Freeze,

§

impl<F> Send for Task<F>
where Pin<Box<F>>: Send,

§

impl<F> Sync for Task<F>
where Pin<Box<F>>: Sync,

§

impl<F> Unpin for Task<F>
where Pin<Box<F>>: Unpin,

§

impl<F> UnsafeUnpin for Task<F>
where Pin<Box<F>>: UnsafeUnpin,

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> FutureExt for T
where T: Future + ?Sized,

Source§

fn map<U, F>(self, f: F) -> Map<Self, F> ⓘ
where F: FnOnce(Self::Output) -> U, Self: Sized,

Map this future’s output to a different type, returning a new future of the resulting type. Read more
Source§

fn map_into<U>(self) -> MapInto<Self, U> ⓘ
where Self::Output: Into<U>, Self: Sized,

Map this future’s output to a different type, returning a new future of the resulting type. Read more
Source§

fn then<Fut, F>(self, f: F) -> Then<Self, Fut, F> ⓘ
where F: FnOnce(Self::Output) -> Fut, Fut: Future, Self: Sized,

Chain on a computation for when a future finished, passing the result of the future to the provided closure f. Read more
Source§

fn left_future<B>(self) -> Either<Self, B> ⓘ
where B: Future<Output = Self::Output>, Self: Sized,

Wrap this future in an Either future, making it the left-hand variant of that Either. Read more
Source§

fn right_future<A>(self) -> Either<A, Self> ⓘ
where A: Future<Output = Self::Output>, Self: Sized,

Wrap this future in an Either future, making it the right-hand variant of that Either. Read more
Source§

fn into_stream(self) -> IntoStream<Self>
where Self: Sized,

Convert this future into a single element stream. Read more
Source§

fn flatten(self) -> Flatten<Self> ⓘ
where Self::Output: Future, Self: Sized,

Flatten the execution of this future when the output of this future is itself another future. Read more
Source§

fn flatten_stream(self) -> FlattenStream<Self>
where Self::Output: Stream, Self: Sized,

Flatten the execution of this future when the successful result of this future is a stream. Read more
Source§

fn fuse(self) -> Fuse<Self> ⓘ
where Self: Sized,

Fuse a future such that poll will never again be called once it has completed. This method can be used to turn any Future into a FusedFuture. Read more
Source§

fn inspect<F>(self, f: F) -> Inspect<Self, F> ⓘ
where F: FnOnce(&Self::Output), Self: Sized,

Do something with the output of a future before passing it on. Read more
Source§

fn catch_unwind(self) -> CatchUnwind<Self> ⓘ
where Self: Sized + UnwindSafe,

Catches unwinding panics while polling the future. Read more
Source§

fn shared(self) -> Shared<Self> ⓘ
where Self: Sized, Self::Output: Clone,

Create a cloneable handle to this future where all handles will resolve to the same result. Read more
Source§

fn remote_handle(self) -> (Remote<Self>, RemoteHandle<Self::Output>)
where Self: Sized,

Turn this future into a future that yields () on completion and sends its output to another future on a separate task. Read more
Source§

fn boxed<'a>(self) -> Pin<Box<dyn Future<Output = Self::Output> + Send + 'a>>
where Self: Sized + Send + 'a,

Wrap the future in a Box, pinning it. Read more
Source§

fn boxed_local<'a>(self) -> Pin<Box<dyn Future<Output = Self::Output> + 'a>>
where Self: Sized + 'a,

Wrap the future in a Box, pinning it. Read more
Source§

fn unit_error(self) -> UnitError<Self> ⓘ
where Self: Sized,

Source§

fn never_error(self) -> NeverError<Self> ⓘ
where Self: Sized,

Source§

fn poll_unpin(&mut self, cx: &mut Context<'_>) -> Poll<Self::Output>
where Self: Unpin,

A convenience for calling Future::poll on Unpin future types.
Source§

fn now_or_never(self) -> Option<Self::Output>
where Self: Sized,

Evaluates and consumes the future, returning the resulting output if the future is ready after the first call to Future::poll. Read more
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<F> IntoFuture for F
where F: Future,

Source§

type Output = <F as Future>::Output

The output that the future will produce on completion.
Source§

type IntoFuture = F

Which kind of future are we turning this into?
Source§

fn into_future(self) -> <F as IntoFuture>::IntoFuture

Creates a future from a value. Read more
Source§

impl<T> TaskExt for T
where T: Future,

Source§

fn delay(self, after: Duration) -> Delay<Self> ⓘ
where Self: Sized,

Delays the start of this future by the specified duration. Read more
Source§

fn timeout(self, time_limit: Duration) -> Timeout<Self> ⓘ
where Self: Sized,

Applies a timeout to this future, returning a default value if it doesn’t complete in time. Read more
Source§

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

Source§

type Error = !

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

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<F, T, E> TryFuture for F
where F: Future<Output = Result<T, E>> + ?Sized,

Source§

type Ok = T

The type of successful values yielded by this future
Source§

type Error = E

The type of failures yielded by this future
Source§

fn try_poll( self: Pin<&mut F>, cx: &mut Context<'_>, ) -> Poll<<F as Future>::Output>

Poll this TryFuture as if it were a Future. Read more
Source§

impl<Fut> TryFutureExt for Fut
where Fut: TryFuture + ?Sized,

Source§

fn flatten_sink<Item>(self) -> FlattenSink<Self, Self::Ok>
where Self::Ok: Sink<Item, Error = Self::Error>, Self: Sized,

Flattens the execution of this future when the successful result of this future is a Sink. Read more
Source§

fn map_ok<T, F>(self, f: F) -> MapOk<Self, F> ⓘ
where F: FnOnce(Self::Ok) -> T, Self: Sized,

Maps this future’s success value to a different value. Read more
Source§

fn map_ok_or_else<T, E, F>(self, e: E, f: F) -> MapOkOrElse<Self, F, E> ⓘ
where F: FnOnce(Self::Ok) -> T, E: FnOnce(Self::Error) -> T, Self: Sized,

Maps this future’s success value to a different value, and permits for error handling resulting in the same type. Read more
Source§

fn map_err<E, F>(self, f: F) -> MapErr<Self, F> ⓘ
where F: FnOnce(Self::Error) -> E, Self: Sized,

Maps this future’s error value to a different value. Read more
Source§

fn err_into<E>(self) -> ErrInto<Self, E> ⓘ
where Self: Sized, Self::Error: Into<E>,

Maps this future’s Error to a new error type using the Into trait. Read more
Source§

fn ok_into<U>(self) -> OkInto<Self, U> ⓘ
where Self: Sized, Self::Ok: Into<U>,

Maps this future’s Ok to a new type using the Into trait.
Source§

fn and_then<Fut, F>(self, f: F) -> AndThen<Self, Fut, F> ⓘ
where F: FnOnce(Self::Ok) -> Fut, Fut: TryFuture<Error = Self::Error>, Self: Sized,

Executes another future after this one resolves successfully. The success value is passed to a closure to create this subsequent future. Read more
Source§

fn or_else<Fut, F>(self, f: F) -> OrElse<Self, Fut, F> ⓘ
where F: FnOnce(Self::Error) -> Fut, Fut: TryFuture<Ok = Self::Ok>, Self: Sized,

Executes another future if this one resolves to an error. The error value is passed to a closure to create this subsequent future. Read more
Source§

fn inspect_ok<F>(self, f: F) -> InspectOk<Self, F> ⓘ
where F: FnOnce(&Self::Ok), Self: Sized,

Do something with the success value of a future before passing it on. Read more
Source§

fn inspect_err<F>(self, f: F) -> InspectErr<Self, F> ⓘ
where F: FnOnce(&Self::Error), Self: Sized,

Do something with the error value of a future before passing it on. Read more
Source§

fn try_flatten(self) -> TryFlatten<Self, Self::Ok> ⓘ
where Self::Ok: TryFuture<Error = Self::Error>, Self: Sized,

Flatten the execution of this future when the successful result of this future is another future. Read more
Source§

fn try_flatten_stream(self) -> TryFlattenStream<Self>
where Self::Ok: TryStream<Error = Self::Error>, Self: Sized,

Flatten the execution of this future when the successful result of this future is a stream. Read more
Source§

fn unwrap_or_else<F>(self, f: F) -> UnwrapOrElse<Self, F> ⓘ
where Self: Sized, F: FnOnce(Self::Error) -> Self::Ok,

Unwraps this future’s output, producing a future with this future’s Ok type as its Output type. Read more
Source§

fn into_future(self) -> IntoFuture<Self> ⓘ
where Self: Sized,

Wraps a TryFuture into a type that implements Future. Read more
Source§

fn try_poll_unpin( &mut self, cx: &mut Context<'_>, ) -> Poll<Result<Self::Ok, Self::Error>>
where Self: Unpin,

A convenience method for calling TryFuture::try_poll on Unpin future types.
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.