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 typeN- The notification type (useInfallibleif 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>
impl<F: Future<Output = ()>, N> Task<F, N>
Sourcepub fn spawn_current(self)
pub fn spawn_current(self)
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();Sourcepub fn spawn_local_current(self)where
F: 'static,
N: ObserverNotified<()> + 'static,
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 beSend) - 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();Sourcepub fn spawn_static_current(self)where
F: 'static,
N: ObserverNotified<()> + 'static,
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 beSend) - 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>
impl<F: Future, N> Task<F, N>
Sourcepub fn pin_current(self) -> impl Future<Output = F::Output> + Send
pub fn pin_current(self) -> impl Future<Output = 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:
- Use Send/Sync types where possible (
Arcinstead ofRc) - 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)
- Use
SomeStaticExecutormethods 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
crate::thread_executor::pin_static_to_threadfor a more general-purpose pinning function
Source§impl Task<BoxedSendFuture, BoxedSendObserverNotifier>
impl Task<BoxedSendFuture, BoxedSendObserverNotifier>
Sourcepub 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
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 taskfuture- A boxed future that outputs a boxedAny + Sendvalueconfiguration- Runtime hints and scheduling preferencesnotifier- 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>
impl Task<BoxedLocalFuture, BoxedLocalObserverNotifier>
Sourcepub 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
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 taskfuture- A boxed future that outputs a boxedAnyvalueconfiguration- Runtime hints and scheduling preferencesnotifier- 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,
);Sourcepub 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
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>
impl<F: Future, N> Task<F, N>
Sourcepub fn spawn<Executor: SomeExecutor>(
self,
executor: &mut Executor,
) -> SpawnResult<F, N, Executor>
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:
- A
spawned::SpawnedTaskthat can be polled by the executor - A
TypedObserverthat 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.
Sourcepub fn spawn_local<'executor, Executor: SomeLocalExecutor<'executor>>(
self,
executor: &mut Executor,
) -> SpawnLocalResult<'executor, F, N, Executor>
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:
- A
spawned::SpawnedLocalTaskthat can be polled by the executor - A
TypedObserverthat 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);Sourcepub fn spawn_static<Executor: SomeStaticExecutor>(
self,
executor: &mut Executor,
) -> SpawnStaticResult<F, N, Executor>
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:
- A
spawned::SpawnedStaticTaskthat can be polled by the executor - A
TypedObserverthat 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);Sourcepub fn spawn_objsafe<Executor: SomeExecutor>(
self,
executor: &mut Executor,
) -> SpawnObjSafeResult<F, N, Executor>
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:
- A
spawned::SpawnedTaskwith the concrete future type - A
TypedObserverwith 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 notifierSourcepub fn spawn_local_objsafe<'executor, Executor: SomeLocalExecutor<'executor>>(
self,
executor: &mut Executor,
) -> SpawnLocalObjSafeResult<F, N, Executor>
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:
- A
spawned::SpawnedLocalTaskwith the concrete future type - A
TypedObserverwith 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);Sourcepub fn spawn_static_objsafe<Executor: SomeStaticExecutor>(
self,
executor: &mut Executor,
) -> SpawnStaticObjSafeResult<F, N, Executor>
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:
- A
spawned::SpawnedStaticTaskthat can be polled by the executor - A
TypedObserverthat can be used to await or check the task’s completion
Sourcepub fn into_objsafe(self) -> ObjSafeTask
pub fn into_objsafe(self) -> ObjSafeTask
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`Sourcepub fn into_objsafe_local(self) -> ObjSafeLocalTask
pub fn into_objsafe_local(self) -> ObjSafeLocalTask
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 necessarilySend) - 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`Sourcepub fn into_objsafe_static(self) -> ObjSafeStaticTask
pub fn into_objsafe_static(self) -> ObjSafeStaticTask
Converts this task into one suitable for spawn_static_objsafe
Source§impl<F: Future, N> Task<F, N>
impl<F: Future, N> Task<F, N>
Sourcepub fn with_notifications(
label: String,
configuration: Configuration,
notifier: Option<N>,
future: F,
) -> Selfwhere
F: Future,
pub fn with_notifications(
label: String,
configuration: Configuration,
notifier: Option<N>,
future: F,
) -> Selfwhere
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 monitoringconfiguration- Runtime hints and scheduling preferencesnotifier- Optional observer to notify on task completionfuture- 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 }
);Sourcepub fn hint(&self) -> Hint
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.
Sourcepub fn label(&self) -> &str
pub fn label(&self) -> &str
Returns the human-readable label for this task.
Labels are useful for debugging, monitoring, and identifying tasks in logs.
Sourcepub fn priority(&self) -> Priority
pub fn priority(&self) -> Priority
Returns the priority of this task.
Priority influences scheduling decisions when multiple tasks are ready to run.
Sourcepub fn poll_after(&self) -> Instant
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"); },
);Sourcepub fn task_id(&self) -> TaskID
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.
Sourcepub fn into_future(self) -> F
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>
impl<F: Future> Task<F, Infallible>
Sourcepub fn without_notifications(
label: String,
configuration: Configuration,
future: F,
) -> Self
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 monitoringconfiguration- Runtime hints and scheduling preferencesfuture- 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
}
);