1use std::{future::Future, time::Duration};
8
9#[cfg(target_vendor = "apple")]
10mod apple;
11use executor_core::{Executor, LocalExecutor, async_task::AsyncTask};
12
13#[cfg(target_os = "android")]
14pub mod android;
15#[cfg(target_arch = "wasm32")]
16mod web;
17
18#[cfg(any(
19 all(feature = "polyfill", not(target_arch = "wasm32")),
20 target_os = "android"
21))]
22pub mod polyfill;
23
24#[cfg(all(
25 not(feature = "polyfill"),
26 not(target_vendor = "apple"),
27 not(target_os = "android"),
28 not(target_arch = "wasm32")
29))]
30compile_error!(
31 "native-executor has no backend for this target; enable the `polyfill` feature \
32 to build on unsupported platforms."
33);
34
35#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
49#[non_exhaustive]
50pub enum Priority {
51 #[default]
56 Default,
57 Background,
63 UserInitiated,
67 UserInteractive,
73 Utility,
78}
79
80trait PlatformExecutor {
81 type Timer: Future<Output = ()>;
82 fn with_priority(priority: Priority) -> Self;
83 fn sleep(duration: Duration) -> Self::Timer;
84 fn spawn<Fut>(&self, fut: Fut) -> AsyncTask<Fut::Output>
85 where
86 Fut: Future<Output: Send> + Send + 'static;
87 fn spawn_main<Fut>(&self, fut: Fut) -> AsyncTask<Fut::Output>
88 where
89 Fut: Future<Output: Send> + Send + 'static;
90 fn spawn_main_local<Fut>(&self, fut: Fut) -> AsyncTask<Fut::Output>
91 where
92 Fut: Future + 'static;
93}
94
95#[cfg(target_vendor = "apple")]
96type NativeExecutorInner = apple::AppleExecutor;
97
98#[cfg(target_os = "android")]
99type NativeExecutorInner = android::AndroidExecutor;
100
101#[cfg(target_arch = "wasm32")]
102type NativeExecutorInner = web::WebExecutor;
103
104#[cfg(all(
105 feature = "polyfill",
106 not(any(target_vendor = "apple", target_os = "android", target_arch = "wasm32"))
107))]
108type NativeExecutorInner = polyfill::executor::PolyfillExecutor;
109
110#[cfg(target_os = "android")]
111pub use android::register_android_main_thread;
112
113#[derive(Debug)]
114pub struct NativeExecutor(NativeExecutorInner);
115
116impl Default for NativeExecutor {
117 fn default() -> Self {
118 Self::new()
119 }
120}
121
122impl NativeExecutor {
123 #[must_use]
124 pub fn new() -> Self {
125 Self::with_priority(Priority::default())
126 }
127
128 #[must_use]
129 pub fn with_priority(priority: Priority) -> Self {
130 Self(<NativeExecutorInner as PlatformExecutor>::with_priority(
131 priority,
132 ))
133 }
134
135 pub fn spawn_main<Fut>(&self, fut: Fut) -> AsyncTask<Fut::Output>
136 where
137 Fut: Future<Output: Send> + Send + 'static,
138 {
139 <NativeExecutorInner as PlatformExecutor>::spawn_main(&self.0, fut)
140 }
141
142 pub fn spawn<Fut>(&self, fut: Fut) -> AsyncTask<Fut::Output>
143 where
144 Fut: Future<Output: Send> + Send + 'static,
145 {
146 <NativeExecutorInner as PlatformExecutor>::spawn(&self.0, fut)
147 }
148
149 pub fn spawn_main_local<Fut>(&self, fut: Fut) -> <Self as LocalExecutor>::Task<Fut::Output>
150 where
151 Fut: Future + 'static,
152 {
153 <NativeExecutorInner as PlatformExecutor>::spawn_main_local(&self.0, fut)
154 }
155}
156
157#[derive(Debug)]
159pub struct NativeTimer(<NativeExecutorInner as PlatformExecutor>::Timer);
160
161impl NativeTimer {
162 #[must_use]
163 pub fn after(duration: Duration) -> Self {
164 Self(<NativeExecutorInner as PlatformExecutor>::sleep(duration))
165 }
166}
167
168impl Future for NativeTimer {
169 type Output = ();
170 fn poll(
171 mut self: std::pin::Pin<&mut Self>,
172 cx: &mut std::task::Context<'_>,
173 ) -> std::task::Poll<Self::Output> {
174 std::pin::pin!(&mut self.0).poll(cx)
175 }
176}
177
178impl Executor for NativeExecutor {
179 type Task<T: Send + 'static> = AsyncTask<T>;
180 fn spawn<Fut>(&self, fut: Fut) -> Self::Task<Fut::Output>
181 where
182 Fut: Future<Output: Send> + Send + 'static,
183 {
184 <NativeExecutorInner as PlatformExecutor>::spawn(&self.0, fut)
185 }
186}
187
188impl LocalExecutor for NativeExecutor {
191 type Task<T: 'static> = AsyncTask<T>;
192 fn spawn_local<Fut>(&self, fut: Fut) -> Self::Task<Fut::Output>
193 where
194 Fut: Future + 'static,
195 {
196 <NativeExecutorInner as PlatformExecutor>::spawn_main_local(&self.0, fut)
197 }
198}
199
200#[must_use]
201pub fn sleep(duration: Duration) -> NativeTimer {
202 NativeTimer::after(duration)
203}