native_executor/lib.rs
1#![doc = include_str!("../README.md")]
2#![no_std]
3#![warn(missing_docs, missing_debug_implementations)]
4extern crate alloc;
5
6#[cfg(target_vendor = "apple")]
7mod apple;
8
9#[cfg(all(not(target_vendor = "apple"), not(docsrs)))]
10compile_error!("native_executor currently only supports Apple platforms, more to come soon!");
11
12use async_task::Task;
13use executor_core::{Executor, LocalExecutor};
14pub mod mailbox;
15pub mod timer;
16use core::time::Duration;
17
18#[cfg(target_vendor = "apple")]
19pub use apple::ApplePlatformExecutor as NativeExecutor;
20
21mod unsupported {
22 use core::time::Duration;
23
24 use crate::{PlatformExecutor, Priority};
25
26 #[allow(unused)]
27 /// A stub executor for unsupported platforms that panics on use.
28 pub struct UnsupportedExecutor;
29 impl PlatformExecutor for UnsupportedExecutor {
30 fn exec_main(_f: impl FnOnce() + Send + 'static) {
31 panic!("exec_main is not supported on this platform");
32 }
33
34 fn exec(_f: impl FnOnce() + Send + 'static, _priority: Priority) {
35 panic!("exec is not supported on this platform");
36 }
37
38 fn exec_after(_delay: Duration, _f: impl FnOnce() + Send + 'static) {
39 panic!("exec_after is not supported on this platform");
40 }
41 }
42}
43
44#[cfg(not(target_vendor = "apple"))]
45/// The native executor implementation.
46pub use unsupported::UnsupportedExecutor as NativeExecutor;
47
48trait PlatformExecutor {
49 fn exec_main(f: impl FnOnce() + Send + 'static);
50 fn exec(f: impl FnOnce() + Send + 'static, priority: Priority);
51
52 fn exec_after(delay: Duration, f: impl FnOnce() + Send + 'static);
53}
54
55impl Executor for NativeExecutor {
56 fn spawn<T: Send + 'static>(&self, fut: impl Future<Output = T> + Send + 'static) -> Task<T> {
57 spawn(fut)
58 }
59}
60
61impl LocalExecutor for NativeExecutor {
62 fn spawn_local<T: 'static>(&self, fut: impl Future<Output = T> + 'static) -> Task<T> {
63 spawn_local(fut)
64 }
65}
66
67use async_task::Runnable;
68
69/// Task execution priority levels for controlling scheduler behavior.
70///
71/// These priority levels map to platform-native scheduling priorities,
72/// allowing fine-grained control over task execution order and resource allocation.
73#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
74#[non_exhaustive]
75pub enum Priority {
76 /// Standard priority level for most application tasks.
77 ///
78 /// This is the default priority that provides balanced execution
79 /// suitable for general-purpose async operations.
80 #[default]
81 Default,
82 /// Lower priority for background tasks and non-critical operations.
83 ///
84 /// Background tasks yield CPU time to higher-priority tasks and are
85 /// ideal for operations like cleanup, logging, or data processing
86 /// that don't require immediate completion.
87 Background,
88 /// Higher priority for user-initiated tasks that require prompt execution.
89 /// This priority is suitable for tasks that directly impact user experience,
90 /// such as responding to user input or updating the UI.
91 UserInitiated,
92 /// Highest priority for tasks that require immediate attention to maintain
93 /// application responsiveness.
94 /// This priority should be reserved for critical operations that must
95 /// complete as soon as possible, such as rendering UI updates or handling
96 /// real-time data.
97 UserInteractive,
98 /// Lowest priority for tasks that can be deferred until the system is idle.
99 /// This priority is suitable for maintenance tasks, prefetching data,
100 /// or other operations that do not need to run immediately and can wait
101 /// until the system is less busy.
102 Utility,
103}
104
105/// Creates a new task with the specified execution priority.
106///
107/// This allows fine-grained control over task scheduling, enabling
108/// background tasks to yield to higher-priority operations.
109///
110/// # Arguments
111/// * `future` - The future to execute asynchronously
112/// * `priority` - The scheduling priority for this task
113///
114/// # Returns
115/// A `Task` handle that can be awaited to retrieve the result
116///
117/// # Examples
118/// ```rust
119/// use native_executor::{spawn_with_priority, Priority};
120///
121/// // High-priority task for time-sensitive operations
122/// let urgent = spawn_with_priority(async {
123/// // Your time-sensitive work here
124/// 42
125/// }, Priority::Default);
126///
127/// // Background task that won't interfere with UI responsiveness
128/// let cleanup = spawn_with_priority(async {
129/// // Your background work here
130/// "done"
131/// }, Priority::Background);
132/// ```
133pub fn spawn_with_priority<Fut>(future: Fut, priority: Priority) -> Task<Fut::Output>
134where
135 Fut: Future + Send + 'static,
136 Fut::Output: Send,
137{
138 let (runnable, task) = async_task::spawn(future, move |runnable: Runnable| {
139 NativeExecutor::exec(
140 move || {
141 runnable.run();
142 },
143 priority,
144 );
145 });
146
147 runnable.schedule();
148 task
149}
150
151/// Creates a new thread-local task that runs on the main thread.
152///
153/// This function is designed for futures that are not `Send` and must execute
154/// on the main thread.
155///
156/// # Arguments
157/// * `future` - The non-Send future to execute on the main thread
158///
159/// # Returns
160/// A `Task` handle that can be awaited to retrieve the result
161///
162/// # Panics
163/// This function may panic if not called from a main thread
164///
165/// # Examples
166/// ```rust
167/// use native_executor::spawn_local;
168/// use std::rc::Rc;
169///
170/// // Rc is not Send, so we need spawn_local
171/// let local_data = Rc::new(42);
172/// let task = spawn_local(async move {
173/// *local_data + 58
174/// });
175/// ```
176pub fn spawn_local<Fut>(future: Fut) -> Task<Fut::Output>
177where
178 Fut: Future + 'static,
179{
180 let (runnable, task) = async_task::spawn_local(future, move |runnable: Runnable| {
181 NativeExecutor::exec_main(move || {
182 runnable.run();
183 });
184 });
185
186 runnable.schedule();
187 task
188}
189
190/// Creates a new task with default priority.
191///
192/// This is the primary function for spawning async tasks. The task will be
193/// executed with default priority using platform-native scheduling.
194///
195/// # Arguments
196/// * `future` - The future to execute asynchronously
197///
198/// # Returns
199/// A `Task` handle that can be awaited to retrieve the result
200///
201/// # Examples
202/// ```rust
203/// use native_executor::spawn;
204///
205/// let task = spawn(async {
206/// // Your async work here
207/// 42
208/// });
209/// ```
210pub fn spawn<Fut>(future: Fut) -> Task<Fut::Output>
211where
212 Fut: Future + Send + 'static,
213 Fut::Output: Send,
214{
215 spawn_with_priority(future, Priority::default())
216}
217
218/// Creates a new task that executes on the main thread.
219///
220/// This function schedules a `Send` future to run specifically on the main thread.
221/// This is useful for operations that must happen on the main thread, such as
222/// UI updates or accessing main-thread-only APIs.
223///
224/// # Arguments
225/// * `future` - The Send future to execute on the main thread
226///
227/// # Returns
228/// A `Task` handle that can be awaited to retrieve the result
229///
230/// # Examples
231/// ```rust
232/// use native_executor::spawn_main;
233///
234/// let task = spawn_main(async {
235/// // This runs on the main thread
236/// println!("Running on main thread");
237/// "done"
238/// });
239/// ```
240pub fn spawn_main<Fut>(future: Fut) -> Task<Fut::Output>
241where
242 Fut: Future + Send + 'static,
243 Fut::Output: Send,
244{
245 let (runnable, task) = async_task::spawn(future, move |runnable: Runnable| {
246 NativeExecutor::exec_main(move || {
247 runnable.run();
248 });
249 });
250
251 runnable.schedule();
252 task
253}