async_task

Struct Builder

Source
pub struct Builder<M> { /* private fields */ }
Expand description

A builder that creates a new task.

Implementations§

Source§

impl Builder<()>

Source

pub fn new() -> Builder<()>

Creates a new task builder.

By default, this task builder has no metadata. Use the [metadata] method to set the metadata.

§Examples
use async_task::Builder;

let (runnable, task) = Builder::new().spawn(|()| async {}, |_| {});
Source

pub fn metadata<M>(self, metadata: M) -> Builder<M>

Adds metadata to the task.

In certain cases, it may be useful to associate some metadata with a task. For instance, you may want to associate a name with a task, or a priority for a priority queue. This method allows the user to attach arbitrary metadata to a task that is available through the Runnable or the Task.

§Examples

This example creates an executor that associates a “priority” number with each task, and then runs the tasks in order of priority.

use async_task::{Builder, Runnable};
use once_cell::sync::Lazy;
use std::cmp;
use std::collections::BinaryHeap;
use std::sync::Mutex;

/// A wrapper around a `Runnable<usize>` that implements `Ord` so that it can be used in a
/// priority queue.
struct TaskWrapper(Runnable<usize>);

impl PartialEq for TaskWrapper {
    fn eq(&self, other: &Self) -> bool {
        self.0.metadata() == other.0.metadata()
    }
}

impl Eq for TaskWrapper {}

impl PartialOrd for TaskWrapper {
   fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
      Some(self.cmp(other))
   }
}

impl Ord for TaskWrapper {
   fn cmp(&self, other: &Self) -> cmp::Ordering {
       self.0.metadata().cmp(other.0.metadata())
   }
}

static EXECUTOR: Lazy<Mutex<BinaryHeap<TaskWrapper>>> = Lazy::new(|| {
    Mutex::new(BinaryHeap::new())
});

let schedule = |runnable| {
    EXECUTOR.lock().unwrap().push(TaskWrapper(runnable));
};

// Spawn a few tasks with different priorities.
let spawn_task = move |priority| {
    let (runnable, task) = Builder::new().metadata(priority).spawn(
        move |_| async move { priority },
        schedule,
    );
    runnable.schedule();
    task
};

let t1 = spawn_task(1);
let t2 = spawn_task(2);
let t3 = spawn_task(3);

// Run the tasks in order of priority.
let mut metadata_seen = vec![];
while let Some(TaskWrapper(runnable)) = EXECUTOR.lock().unwrap().pop() {
    metadata_seen.push(*runnable.metadata());
    runnable.run();
}

assert_eq!(metadata_seen, vec![3, 2, 1]);
assert_eq!(t1.await, 1);
assert_eq!(t2.await, 2);
assert_eq!(t3.await, 3);
Source§

impl<M> Builder<M>

Source

pub fn propagate_panic(self, propagate_panic: bool) -> Builder<M>

Propagates panics that occur in the task.

When this is true, panics that occur in the task will be propagated to the caller of the Task. When this is false, no special action is taken when a panic occurs in the task, meaning that the caller of Runnable::run will observe a panic.

This is only available when the std feature is enabled. By default, this is false.

§Examples
use async_task::Builder;
use futures_lite::future::poll_fn;
use std::future::Future;
use std::panic;
use std::pin::Pin;
use std::task::{Context, Poll};

fn did_panic<F: FnOnce()>(f: F) -> bool {
    panic::catch_unwind(panic::AssertUnwindSafe(f)).is_err()
}

let (runnable1, mut task1) = Builder::new()
   .propagate_panic(true)
   .spawn(|()| async move { panic!() }, |_| {});

let (runnable2, mut task2) = Builder::new()
   .propagate_panic(false)
   .spawn(|()| async move { panic!() }, |_| {});

assert!(!did_panic(|| { runnable1.run(); }));
assert!(did_panic(|| { runnable2.run(); }));

let waker = poll_fn(|cx| Poll::Ready(cx.waker().clone())).await;
let mut cx = Context::from_waker(&waker);
assert!(did_panic(|| { let _ = Pin::new(&mut task1).poll(&mut cx); }));
assert!(did_panic(|| { let _ = Pin::new(&mut task2).poll(&mut cx); }));
Source

pub fn spawn<F, Fut, S>( self, future: F, schedule: S, ) -> (Runnable<M>, Task<Fut::Output, M>)
where F: FnOnce(&M) -> Fut, Fut: Future + Send + 'static, Fut::Output: Send + 'static, S: Schedule<M> + Send + Sync + 'static,

Creates a new task.

The returned Runnable is used to poll the future, and the Task is used to await its output.

Method run() polls the task’s future once. Then, the Runnable vanishes and only reappears when its Waker wakes the task, thus scheduling it to be run again.

When the task is woken, its Runnable is passed to the schedule function. The schedule function should not attempt to run the Runnable nor to drop it. Instead, it should push it into a task queue so that it can be processed later.

If you need to spawn a future that does not implement Send or isn’t 'static, consider using spawn_local() or spawn_unchecked() instead.

§Examples
use async_task::Builder;

// The future inside the task.
let future = async {
    println!("Hello, world!");
};

// A function that schedules the task when it gets woken up.
let (s, r) = flume::unbounded();
let schedule = move |runnable| s.send(runnable).unwrap();

// Create a task with the future and the schedule function.
let (runnable, task) = Builder::new().spawn(|()| future, schedule);
Source

pub fn spawn_local<F, Fut, S>( self, future: F, schedule: S, ) -> (Runnable<M>, Task<Fut::Output, M>)
where F: FnOnce(&M) -> Fut, Fut: Future + 'static, Fut::Output: 'static, S: Schedule<M> + Send + Sync + 'static,

Creates a new thread-local task.

This function is same as spawn(), except it does not require Send on future. If the Runnable is used or dropped on another thread, a panic will occur.

This function is only available when the std feature for this crate is enabled.

§Examples
use async_task::{Builder, Runnable};
use flume::{Receiver, Sender};
use std::rc::Rc;

thread_local! {
    // A queue that holds scheduled tasks.
    static QUEUE: (Sender<Runnable>, Receiver<Runnable>) = flume::unbounded();
}

// Make a non-Send future.
let msg: Rc<str> = "Hello, world!".into();
let future = async move {
    println!("{}", msg);
};

// A function that schedules the task when it gets woken up.
let s = QUEUE.with(|(s, _)| s.clone());
let schedule = move |runnable| s.send(runnable).unwrap();

// Create a task with the future and the schedule function.
let (runnable, task) = Builder::new().spawn_local(move |()| future, schedule);
Source

pub unsafe fn spawn_unchecked<'a, F, Fut, S>( self, future: F, schedule: S, ) -> (Runnable<M>, Task<Fut::Output, M>)
where F: FnOnce(&'a M) -> Fut, Fut: Future + 'a, S: Schedule<M>, M: 'a,

Creates a new task without Send, Sync, and 'static bounds.

This function is same as spawn(), except it does not require Send, Sync, and 'static on future and schedule.

§Safety
  • If Fut is not Send, its Runnable must be used and dropped on the original thread.
  • If Fut is not 'static, borrowed non-metadata variables must outlive its Runnable.
  • If schedule is not Send and Sync, all instances of the Runnable’s Waker must be used and dropped on the original thread.
  • If schedule is not 'static, borrowed variables must outlive all instances of the Runnable’s Waker.
§Examples
use async_task::Builder;

// The future inside the task.
let future = async {
    println!("Hello, world!");
};

// If the task gets woken up, it will be sent into this channel.
let (s, r) = flume::unbounded();
let schedule = move |runnable| s.send(runnable).unwrap();

// Create a task with the future and the schedule function.
let (runnable, task) = unsafe { Builder::new().spawn_unchecked(move |()| future, schedule) };

Trait Implementations§

Source§

impl<M: Debug> Debug for Builder<M>

Source§

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

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

impl<M: Default> Default for Builder<M>

Source§

fn default() -> Self

Returns the “default value” for a type. Read more

Auto Trait Implementations§

§

impl<M> Freeze for Builder<M>
where M: Freeze,

§

impl<M> RefUnwindSafe for Builder<M>
where M: RefUnwindSafe,

§

impl<M> Send for Builder<M>
where M: Send,

§

impl<M> Sync for Builder<M>
where M: Sync,

§

impl<M> Unpin for Builder<M>
where M: Unpin,

§

impl<M> UnwindSafe for Builder<M>
where M: UnwindSafe,

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.