use std::{future::Future, time::Duration};
#[cfg(target_vendor = "apple")]
mod apple;
use executor_core::{Executor, LocalExecutor, async_task::AsyncTask};
#[cfg(target_os = "android")]
pub mod android;
#[cfg(target_arch = "wasm32")]
mod web;
#[cfg(any(
all(feature = "polyfill", not(target_arch = "wasm32")),
target_os = "android"
))]
pub mod polyfill;
#[cfg(all(
not(feature = "polyfill"),
not(target_vendor = "apple"),
not(target_os = "android"),
not(target_arch = "wasm32")
))]
compile_error!(
"native-executor has no backend for this target; enable the `polyfill` feature \
to build on unsupported platforms."
);
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
pub enum Priority {
#[default]
Default,
Background,
UserInitiated,
UserInteractive,
Utility,
}
trait PlatformExecutor {
type Timer: Future<Output = ()>;
fn with_priority(priority: Priority) -> Self;
fn sleep(duration: Duration) -> Self::Timer;
fn spawn<Fut>(&self, fut: Fut) -> AsyncTask<Fut::Output>
where
Fut: Future<Output: Send> + Send + 'static;
fn spawn_main<Fut>(&self, fut: Fut) -> AsyncTask<Fut::Output>
where
Fut: Future<Output: Send> + Send + 'static;
fn spawn_main_local<Fut>(&self, fut: Fut) -> AsyncTask<Fut::Output>
where
Fut: Future + 'static;
}
#[cfg(target_vendor = "apple")]
type NativeExecutorInner = apple::AppleExecutor;
#[cfg(target_os = "android")]
type NativeExecutorInner = android::AndroidExecutor;
#[cfg(target_arch = "wasm32")]
type NativeExecutorInner = web::WebExecutor;
#[cfg(all(
feature = "polyfill",
not(any(target_vendor = "apple", target_os = "android", target_arch = "wasm32"))
))]
type NativeExecutorInner = polyfill::executor::PolyfillExecutor;
#[cfg(target_os = "android")]
pub use android::register_android_main_thread;
#[derive(Debug)]
pub struct NativeExecutor(NativeExecutorInner);
impl Default for NativeExecutor {
fn default() -> Self {
Self::new()
}
}
impl NativeExecutor {
#[must_use]
pub fn new() -> Self {
Self::with_priority(Priority::default())
}
#[must_use]
pub fn with_priority(priority: Priority) -> Self {
Self(<NativeExecutorInner as PlatformExecutor>::with_priority(
priority,
))
}
pub fn spawn_main<Fut>(&self, fut: Fut) -> AsyncTask<Fut::Output>
where
Fut: Future<Output: Send> + Send + 'static,
{
<NativeExecutorInner as PlatformExecutor>::spawn_main(&self.0, fut)
}
pub fn spawn<Fut>(&self, fut: Fut) -> AsyncTask<Fut::Output>
where
Fut: Future<Output: Send> + Send + 'static,
{
<NativeExecutorInner as PlatformExecutor>::spawn(&self.0, fut)
}
pub fn spawn_main_local<Fut>(&self, fut: Fut) -> <Self as LocalExecutor>::Task<Fut::Output>
where
Fut: Future + 'static,
{
<NativeExecutorInner as PlatformExecutor>::spawn_main_local(&self.0, fut)
}
}
#[derive(Debug)]
pub struct NativeTimer(<NativeExecutorInner as PlatformExecutor>::Timer);
impl NativeTimer {
#[must_use]
pub fn after(duration: Duration) -> Self {
Self(<NativeExecutorInner as PlatformExecutor>::sleep(duration))
}
}
impl Future for NativeTimer {
type Output = ();
fn poll(
mut self: std::pin::Pin<&mut Self>,
cx: &mut std::task::Context<'_>,
) -> std::task::Poll<Self::Output> {
std::pin::pin!(&mut self.0).poll(cx)
}
}
impl Executor for NativeExecutor {
type Task<T: Send + 'static> = AsyncTask<T>;
fn spawn<Fut>(&self, fut: Fut) -> Self::Task<Fut::Output>
where
Fut: Future<Output: Send> + Send + 'static,
{
<NativeExecutorInner as PlatformExecutor>::spawn(&self.0, fut)
}
}
impl LocalExecutor for NativeExecutor {
type Task<T: 'static> = AsyncTask<T>;
fn spawn_local<Fut>(&self, fut: Fut) -> Self::Task<Fut::Output>
where
Fut: Future + 'static,
{
<NativeExecutorInner as PlatformExecutor>::spawn_main_local(&self.0, fut)
}
}
#[must_use]
pub fn sleep(duration: Duration) -> NativeTimer {
NativeTimer::after(duration)
}