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