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