moirai_core/executor/spawner.rs
1//! Task spawning interface.
2
3use crate::error::ExecutorResult;
4use crate::{Priority, Task, TaskHandle};
5
6/// Core task spawning capabilities.
7///
8/// This trait provides the fundamental ability to spawn tasks for execution.
9/// It follows the Single Responsibility Principle by focusing only on task spawning.
10///
11/// # Behavior Guarantees
12/// - Task spawning is non-blocking and returns immediately
13/// - Tasks are scheduled for execution but may not start immediately
14/// - Task handles can be used to wait for completion or cancel tasks
15/// - Memory ordering follows acquire-release semantics for task state
16///
17/// # Performance Characteristics
18/// - Task spawn: O(1) amortized, < 100ns typical latency
19/// - Memory overhead: < 64 bytes per task
20/// - Thread-safe: All operations are safe for concurrent access
21pub trait TaskSpawner: Send + Sync + 'static {
22 /// Spawns a new task for execution.
23 ///
24 /// # Arguments
25 /// * `task` - The task to be executed
26 ///
27 /// # Returns
28 /// A handle to the spawned task that allows monitoring and control
29 ///
30 /// # Errors
31 /// Returns `TaskError::SpawnFailed` if the task cannot be spawned due to:
32 /// - Resource exhaustion (queue full, memory limit reached)
33 /// - Task validation failures (invalid priority, security constraints)
34 /// - System shutdown in progress
35 fn spawn<T>(&self, task: T) -> ExecutorResult<TaskHandle<T::Output>>
36 where
37 T: Task + Send + 'static;
38
39 /// Spawns an asynchronous task (Future) for execution.
40 ///
41 /// # Arguments
42 /// * `future` - The future to be executed
43 ///
44 /// # Returns
45 /// A handle to the spawned task
46 ///
47 /// # Errors
48 /// Returns `TaskError::SpawnFailed` under the same conditions as `spawn`
49 fn spawn_async<F>(&self, future: F) -> ExecutorResult<TaskHandle<F::Output>>
50 where
51 F: core::future::Future + Send + 'static,
52 F::Output: Send + 'static;
53
54 /// Spawns a blocking task that may perform I/O or CPU-intensive work.
55 ///
56 /// # Arguments
57 /// * `func` - The blocking function to execute
58 ///
59 /// # Returns
60 /// A handle to the spawned task
61 ///
62 /// # Errors
63 /// Returns `TaskError::SpawnFailed` under the same conditions as `spawn`
64 fn spawn_blocking<F, R>(&self, func: F) -> ExecutorResult<TaskHandle<R>>
65 where
66 F: FnOnce() -> R + Send + 'static,
67 R: Send + 'static;
68
69 /// Spawns a fire-and-forget task whose result is discarded.
70 ///
71 /// Unlike [`spawn_blocking`](Self::spawn_blocking), the caller receives no
72 /// handle, so an implementation can avoid the per-task
73 /// `Arc<TaskResultSlot>` heap allocation and its atomic reference counting
74 /// that result-bearing spawns require. The task is still tracked for
75 /// graceful-shutdown drain and metrics; it always runs to completion (there
76 /// is no handle to drop, so dropping is not a cancellation path).
77 ///
78 /// The provided default routes through
79 /// [`spawn_blocking`](Self::spawn_blocking) and discards the handle, so it
80 /// still allocates a result slot; implementations should override it to
81 /// skip that allocation.
82 ///
83 /// # Errors
84 /// Returns `TaskError::SpawnFailed` under the same conditions as
85 /// [`spawn`](Self::spawn).
86 fn spawn_detached<F>(&self, func: F) -> ExecutorResult<()>
87 where
88 F: FnOnce() + Send + 'static,
89 {
90 self.spawn_blocking(func).map(drop)
91 }
92
93 /// Spawns a task with specific priority and scheduling hints.
94 ///
95 /// # Arguments
96 /// * `task` - The task to be executed
97 /// * `priority` - The scheduling priority for this task
98 /// * `locality_hint` - Optional hint about preferred execution location
99 ///
100 /// # Returns
101 /// A handle to the spawned task
102 ///
103 /// # Errors
104 /// Returns `TaskError::SpawnFailed` under the same conditions as `spawn`
105 fn spawn_with_priority<T>(
106 &self,
107 task: T,
108 priority: Priority,
109 locality_hint: Option<usize>,
110 ) -> ExecutorResult<TaskHandle<T::Output>>
111 where
112 T: Task + Send + 'static;
113
114 /// Spawn a task on the current thread's local queue for better locality
115 /// (inspired by Tokio's `spawn_local`)
116 fn spawn_local<T>(&self, task: T) -> ExecutorResult<TaskHandle<T::Output>>
117 where
118 T: Task + 'static,
119 {
120 // Default implementation falls back to regular spawn
121 // Executors can override for better locality
122 self.spawn(task)
123 }
124}