Skip to main content

Task

Struct Task 

Source
pub struct Task<F, N>
where F: Future,
{ /* private fields */ }
Expand description

A top-level future with associated metadata for execution.

Task wraps a future with additional information that helps executors make scheduling decisions and provides context during execution. Unlike raw futures, tasks carry metadata such as:

  • A human-readable label for debugging and monitoring
  • Execution hints (e.g., whether the task will block)
  • Priority information for scheduling
  • Optional notification callbacks for completion
  • A unique task ID for tracking

§Type Parameters

  • F - The underlying future type
  • N - The notification type (use Infallible if no notifications are needed)

§Examples

§Creating a simple task

use some_executor::task::{Task, Configuration};
use std::convert::Infallible;

let task: Task<_, Infallible> = Task::without_notifications(
    "fetch-data".to_string(),
    Configuration::default(),
    async {
        // Simulate fetching data
        "data from server"
    },
);

§Creating a task with notifications

use some_executor::task::{Task, Configuration};
use some_executor::observer::ObserverNotified;

let notifier = MyNotifier;

let task = Task::with_notifications(
    "process-request".to_string(),
    Configuration::default(),
    Some(notifier),
    async {
        // Process and return result
        "processed".to_string()
    }
);

Implementations§

Source§

impl<F: Future<Output = ()>, N> Task<F, N>

Source

pub fn spawn_current(self)
where F: Send + 'static, N: ObserverNotified<()> + Send + 'static,

Spawns the task onto the current executor and detaches the observer.

This is a convenience method for fire-and-forget tasks that don’t return a value. The task will be spawned using current_executor and the observer will be automatically detached.

§Requirements
  • The future must output ()
  • The future must be Send + 'static
  • The notifier must be Send + 'static
§Examples
use some_executor::task::{Task, Configuration};

let task = Task::without_notifications(
    "background-work".to_string(),
    Configuration::default(),
    async {
        println!("Running in background");
    },
);

// Spawn and forget
task.spawn_current();
Source

pub fn spawn_local_current(self)
where F: 'static, N: ObserverNotified<()> + 'static,

Spawns the task onto the current thread-local executor and detaches the observer.

This is a convenience method for fire-and-forget tasks that don’t return a value and may not be Send. The task will be spawned using the current thread-local executor and the observer will be automatically detached.

§Requirements
  • The future must output ()
  • The future must be 'static (but doesn’t need to be Send)
  • The notifier must implement ObserverNotified<()>
§Examples
use some_executor::task::{Task, Configuration};
use std::rc::Rc;

// Rc is !Send
let data = Rc::new(42);
let data_clone = data.clone();

let task = Task::without_notifications(
    "local-work".to_string(),
    Configuration::default(),
    async move {
        println!("Local data: {}", data_clone);
    },
);

// Spawn on current thread-local executor
task.spawn_local_current();
Source

pub fn spawn_static_current(self)
where F: 'static, N: ObserverNotified<()> + 'static,

Spawns the task onto the current thread’s static executor and detaches the observer.

This is a convenience method for fire-and-forget tasks that don’t return a value and need to be executed on the current thread’s static executor. The task will be spawned using thread_static_executor and the observer will be automatically detached.

§Requirements
  • The future must output ()
  • The future must be 'static (but doesn’t need to be Send)
  • The notifier must implement ObserverNotified<()> and be 'static
§Examples
use some_executor::task::{Task, Configuration};

let task = Task::without_notifications(
    "static-work".to_string(),
    Configuration::default(),
    async {
        println!("Running on static executor");
    },
);

// Spawn on the thread's static executor
task.spawn_static_current();
Source§

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

Source

pub fn pin_current(self) -> impl Future<Output = F::Output> + Send
where F: 'static, F::Output: Send,

Pins a task to run on the current thread, converting non-Send futures to Send futures.

This method allows you to work with non-Send types (like Rc, RefCell) in an async context by ensuring the task runs only on the current thread.

§When to Use

Use this when:

  • You need to work with non-Send types across await points
  • The executor type is erased or doesn’t support non-Send directly
  • Converting to Send types isn’t feasible
§Trade-offs

Pros:

  • Enables use of non-Send types in async code
  • Works with any executor type

Cons:

  • Task cannot be moved between threads (less efficient)
  • Small runtime overhead for the Send/!Send bridge
  • Task spawns immediately (before the returned future is polled)
  • Limited cancellation support
§Alternatives

Consider these alternatives before using this method:

  1. Use Send/Sync types where possible (Arc instead of Rc)
  2. Scope non-Send types to avoid holding them across await points (see https://rust-lang.github.io/async-book/07_workarounds/03_send_approximation.html)
  3. Use SomeStaticExecutor methods directly if the concrete type supports it
§Examples
use some_executor::task::{Task, Configuration};
use std::rc::Rc;

// Rc is !Send
let data = Rc::new(vec![1, 2, 3]);
let data_clone = data.clone();

let task = Task::without_notifications(
    "process-local-data".to_string(),
    Configuration::default(),
    async move {
        // Can use Rc across await points
        println!("Data: {:?}", data_clone);
        data_clone.len()
    }
);

// Convert to Send future that runs on current thread
let send_future = task.pin_current();
let result = send_future.await;
assert_eq!(result, 3);
§See Also
Source§

impl Task<BoxedSendFuture, BoxedSendObserverNotifier>

Source

pub fn new_objsafe( label: String, future: Box<dyn Future<Output = Box<dyn Any + Send + 'static>> + Send + 'static>, configuration: Configuration, notifier: Option<Box<dyn ObserverNotified<dyn Any + Send> + Send>>, ) -> Self

Creates a new object-safe task for type-erased spawning.

This constructor is used internally to create tasks that can be spawned using object-safe trait methods, where the concrete future type is erased.

§Arguments
  • label - A human-readable label for the task
  • future - A boxed future that outputs a boxed Any + Send value
  • configuration - Runtime hints and scheduling preferences
  • notifier - Optional boxed observer for completion notifications
§Examples
use some_executor::task::{Task, Configuration};
use std::any::Any;

let task = Task::new_objsafe(
    "type-erased".to_string(),
    Box::new(async {
        Box::new(42) as Box<dyn Any + Send>
    }),
    Configuration::default(),
    None,
);
Source§

impl Task<BoxedLocalFuture, BoxedLocalObserverNotifier>

Source

pub fn new_objsafe_local( label: String, future: Box<dyn Future<Output = Box<dyn Any + 'static>> + 'static>, configuration: Configuration, notifier: Option<Box<dyn ObserverNotified<dyn Any + 'static>>>, ) -> Self

Creates a new object-safe task for local (non-Send) type-erased spawning.

This constructor is used internally to create tasks that can be spawned on local executors using object-safe trait methods. The task doesn’t need to be Send but must be 'static.

§Arguments
  • label - A human-readable label for the task
  • future - A boxed future that outputs a boxed Any value
  • configuration - Runtime hints and scheduling preferences
  • notifier - Optional boxed observer for completion notifications
§Examples
use some_executor::task::{Task, Configuration};
use std::any::Any;
use std::rc::Rc;

// Rc is !Send
let data = Rc::new(42);

let task = Task::new_objsafe_local(
    "local-type-erased".to_string(),
    Box::new(async move {
        Box::new(*data) as Box<dyn Any>
    }),
    Configuration::default(),
    None,
);
Source

pub fn new_objsafe_static( label: String, future: Box<dyn Future<Output = Box<dyn Any + 'static>> + 'static>, configuration: Configuration, notifier: Option<Box<dyn ObserverNotified<dyn Any + 'static>>>, ) -> Self

Creates a new task suitable for static objsafe spawning.

This constructor is used internally by into_objsafe_static to create tasks that can be spawned on static executors using object-safe methods.

Source§

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

Source

pub fn spawn<Executor: SomeExecutor>( self, executor: &mut Executor, ) -> SpawnResult<F, N, Executor>

Spawns the task onto an executor.

This method transfers ownership of the task to the executor, which will poll it to completion. It returns a tuple containing:

  1. A spawned::SpawnedTask that can be polled by the executor
  2. A TypedObserver that can be used to await or check the task’s completion
§Arguments
  • executor - The executor that will run this task
§Examples
use std::future::Future;
use std::pin::Pin;
use some_executor::observer::{FinishedObservation, Observer, ObserverNotified, TypedObserver};
use some_executor::task::{Task, Configuration};
use some_executor::SomeExecutor;



let task = Task::without_notifications(
    "compute".to_string(),
    Configuration::default(),
    async { 2 + 2 },
);

let mut executor = MyExecutor;
let (spawned, observer) = task.spawn(&mut executor);

// The task is now owned by the executor
// Use the observer to check completion
§Note

When using this method, the TASK_LOCAL_EXECUTOR will be set to None. To spawn a task onto a local executor instead, use spawn_local.

Source

pub fn spawn_local<'executor, Executor: SomeLocalExecutor<'executor>>( self, executor: &mut Executor, ) -> SpawnLocalResult<'executor, F, N, Executor>

Spawns the task onto a local executor.

Local executors are tied to a specific thread and cannot be sent across threads. This method is similar to spawn but works with executors that are not Send.

§Arguments
  • executor - The local executor that will run this task
§Returns

A tuple containing:

  1. A spawned::SpawnedLocalTask that can be polled by the executor
  2. A TypedObserver that can be used to await or check the task’s completion
§Examples
use some_executor::task::{Task, Configuration};

let mut executor = MyLocalExecutor;

let task = Task::without_notifications(
    "local-work".to_string(),
    Configuration::default(),
    async {
        // Can access thread-local data here
        println!("Running on the local thread");
    },
);

let (spawned, observer) = task.spawn_local(&mut executor);
Source

pub fn spawn_static<Executor: SomeStaticExecutor>( self, executor: &mut Executor, ) -> SpawnStaticResult<F, N, Executor>

Spawns the task onto a static executor.

Static executors handle futures that are 'static but not necessarily Send. This is useful for thread-local executors that work with static data but don’t need to cross thread boundaries.

§Arguments
  • executor - The static executor that will run this task
§Returns

A tuple containing:

  1. A spawned::SpawnedStaticTask that can be polled by the executor
  2. A TypedObserver that can be used to await or check the task’s completion
§Examples
use some_executor::task::{Task, Configuration};

let mut executor = MyStaticExecutor;

let task = Task::without_notifications(
    "static-work".to_string(),
    Configuration::default(),
    async {
        // Can access static data here
        println!("Running on static executor");
    },
);

let (spawned, observer) = task.spawn_static(&mut executor);
Source

pub fn spawn_objsafe<Executor: SomeExecutor>( self, executor: &mut Executor, ) -> SpawnObjSafeResult<F, N, Executor>

Spawns the task onto an executor using object-safe type erasure.

This method enables spawning tasks when the executor type is not known at compile time, using dynamic dispatch instead of static dispatch. The spawner receives type-erased handles while the executor still works with concrete types.

§Object Safety

“Object-safe” here means the method can be called through a trait object (dyn SomeExecutor). This requires:

  • No generic parameters in the trait method signature
  • Type erasure of the future and its output type
§Type Erasure

The method erases types for the spawner but not the executor:

  • Spawner side: Receives boxed, type-erased observer
  • Executor side: Still works with the concrete future type
§Arguments
  • executor - The executor that will run this task
§Returns

A tuple containing:

  1. A spawned::SpawnedTask with the concrete future type
  2. A TypedObserver with a boxed executor notifier
§Examples
let mut executor = TestExecutor;
let task = Task::without_notifications(
    "objsafe-task".to_string(),
    Configuration::default(),
    async { "result" }
);

let (spawned, observer) = task.spawn_objsafe(&mut executor);
// Observer has type-erased executor notifier
Source

pub fn spawn_local_objsafe<'executor, Executor: SomeLocalExecutor<'executor>>( self, executor: &mut Executor, ) -> SpawnLocalObjSafeResult<F, N, Executor>

Spawns the task onto a local executor using object-safe type erasure.

Similar to spawn_objsafe but for local executors that don’t require Send. This enables spawning tasks on thread-local executors when the executor type is not known at compile time.

§Object Safety

This method provides the same type erasure benefits as spawn_objsafe but for local executors. The spawner receives type-erased handles while the executor continues to work with concrete types.

§Arguments
  • executor - The local executor that will run this task
§Returns

A tuple containing:

  1. A spawned::SpawnedLocalTask with the concrete future type
  2. A TypedObserver with a boxed executor notifier
§Examples
let mut executor = TestLocalExecutor;
// Works with !Send types
let data = Rc::new(42);
let data_clone = data.clone();
let task = Task::without_notifications(
    "local-objsafe".to_string(),
    Configuration::default(),
    async move { *data_clone }
);

let (spawned, observer) = task.spawn_local_objsafe(&mut executor);
Source

pub fn spawn_static_objsafe<Executor: SomeStaticExecutor>( self, executor: &mut Executor, ) -> SpawnStaticObjSafeResult<F, N, Executor>

Spawns the task onto a static executor using object-safe method.

This method is similar to spawn_static but uses type erasure to support object-safe trait usage.

§Arguments
  • executor - The static executor that will run this task
§Returns

A tuple containing:

  1. A spawned::SpawnedStaticTask that can be polled by the executor
  2. A TypedObserver that can be used to await or check the task’s completion
Source

pub fn into_objsafe(self) -> ObjSafeTask
where N: ObserverNotified<F::Output> + Send, F::Output: Send + 'static + Unpin, F: Send + 'static,

Converts this task into an object-safe task for type-erased spawning.

This method transforms a concrete task into one that can be spawned using spawn_objsafe on executors accessed through trait objects.

§Requirements
  • Future must be Send + 'static
  • Future output must be Send + 'static + Unpin
  • Notifier must be Send
§Examples
use some_executor::task::{Task, Configuration};

let task = Task::without_notifications(
    "my-task".to_string(),
    Configuration::default(),
    async { 42 }
);

// Convert to object-safe task
let objsafe_task = task.into_objsafe();
// Now can be spawned on `dyn SomeExecutor`
Source

pub fn into_objsafe_local(self) -> ObjSafeLocalTask
where N: ObserverNotified<F::Output>, F::Output: 'static + Unpin, F: 'static,

Converts this task into an object-safe task for local type-erased spawning.

This method transforms a concrete task into one that can be spawned using spawn_local_objsafe on local executors accessed through trait objects.

§Requirements
  • Future must be 'static (but not necessarily Send)
  • Future output must be 'static + Unpin
§Examples
use some_executor::task::{Task, Configuration};
use std::rc::Rc;

// Works with !Send types
let data = Rc::new(vec![1, 2, 3]);
let data_clone = data.clone();
let task = Task::without_notifications(
    "local-task".to_string(),
    Configuration::default(),
    async move { data_clone.len() }
);

// Convert to object-safe local task
let objsafe_task = task.into_objsafe_local();
// Now can be spawned on `dyn SomeLocalExecutor`
Source

pub fn into_objsafe_static(self) -> ObjSafeStaticTask
where N: ObserverNotified<F::Output>, F::Output: 'static + Unpin, F: 'static,

Converts this task into one suitable for spawn_static_objsafe

Source§

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

Source

pub fn with_notifications( label: String, configuration: Configuration, notifier: Option<N>, future: F, ) -> Self
where F: Future,

Creates a new task with optional completion notifications.

This constructor creates a task that can optionally notify an observer when it completes. If you don’t need notifications, consider using without_notifications instead.

§Arguments
  • label - A human-readable label for debugging and monitoring
  • configuration - Runtime hints and scheduling preferences
  • notifier - Optional observer to notify on task completion
  • future - The async computation to execute
§Examples
use some_executor::task::{Task, Configuration};
use some_executor::observer::ObserverNotified;


let task = Task::with_notifications(
    "compute-result".to_string(),
    Configuration::default(),
    Some(MyNotifier),
    async { 42 }
);
Source

pub fn hint(&self) -> Hint

Returns the execution hint for this task.

Hints provide guidance to executors about the expected behavior of the task, such as whether it will block or complete quickly.

Source

pub fn label(&self) -> &str

Returns the human-readable label for this task.

Labels are useful for debugging, monitoring, and identifying tasks in logs.

Source

pub fn priority(&self) -> Priority

Returns the priority of this task.

Priority influences scheduling decisions when multiple tasks are ready to run.

Source

pub fn poll_after(&self) -> Instant

Returns the earliest time this task should be polled.

Executors must not poll the task before this time. This can be used to implement delayed execution or rate limiting.

§Examples
use some_executor::task::{Task, ConfigurationBuilder};
use some_executor::Instant;
use std::time::Duration;

let config = ConfigurationBuilder::new()
    .poll_after(Instant::now() + Duration::from_secs(5))
    .build();

let task = Task::without_notifications(
    "delayed-task".to_string(),
    config,
    async { println!("This runs after 5 seconds"); },
);
Source

pub fn task_id(&self) -> TaskID

Returns the unique identifier for this task.

Task IDs remain constant throughout the task’s lifecycle and can be used for tracking, debugging, and correlation.

Source

pub fn into_future(self) -> F

Consumes the task and returns the underlying future.

This is useful when you need direct access to the future, but note that you’ll lose access to the task’s metadata.

Source§

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

Source

pub fn without_notifications( label: String, configuration: Configuration, future: F, ) -> Self

Creates a task without completion notifications.

This is a convenience constructor for tasks that don’t need observers. It’s equivalent to calling with_notifications with None but avoids the need to specify the notification type parameter.

§Arguments
  • label - A human-readable label for debugging and monitoring
  • configuration - Runtime hints and scheduling preferences
  • future - The async computation to execute
§Examples
use some_executor::task::{Task, Configuration};

let task = Task::without_notifications(
    "background-work".to_string(),
    Configuration::default(),
    async {
        println!("Working in the background");
        42
    }
);

Trait Implementations§

Source§

impl<F: Future, N> AsMut<F> for Task<F, N>

Source§

fn as_mut(&mut self) -> &mut F

Converts this type into a mutable reference of the (usually inferred) input type.
Source§

impl<F: Future, N> AsRef<F> for Task<F, N>

Source§

fn as_ref(&self) -> &F

Converts this type into a shared reference of the (usually inferred) input type.
Source§

impl<F, N: Debug> Debug for Task<F, N>
where F: Future + Debug,

Source§

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

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

impl Default for Task<DefaultFuture, Infallible>

Source§

fn default() -> Self

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

impl<F: Future, N> From<&Task<F, N>> for TaskID

Source§

fn from(task: &Task<F, N>) -> Self

Converts to this type from the input type.
Source§

impl<F: Future, N> From<F> for Task<F, N>

Source§

fn from(future: F) -> Self

Converts to this type from the input type.

Auto Trait Implementations§

§

impl<F, N> Freeze for Task<F, N>
where F: Freeze, N: Freeze,

§

impl<F, N> RefUnwindSafe for Task<F, N>

§

impl<F, N> Send for Task<F, N>
where F: Send, N: Send,

§

impl<F, N> Sync for Task<F, N>
where F: Sync, N: Sync,

§

impl<F, N> Unpin for Task<F, N>
where F: Unpin, N: Unpin,

§

impl<F, N> UnwindSafe for Task<F, N>
where F: UnwindSafe, N: 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.