#![doc = include_str!("../README.md")]
#![cfg_attr(not(feature = "std"), no_std)]
#![forbid(unsafe_code)]
#![deny(warnings, missing_docs)]
#![cfg_attr(docsrs, feature(doc_cfg))]
#![cfg_attr(docsrs, allow(unused_attributes))]
#[cfg(all(feature = "alloc", not(feature = "std")))]
extern crate alloc as std;
#[cfg(feature = "std")]
extern crate std;
macro_rules! cfg_time_with_docsrs {
($($item:item)*) => {
$(
#[cfg(feature = "time")]
#[cfg_attr(docsrs, doc(cfg(feature = "time")))]
$item
)*
};
}
macro_rules! cfg_time {
($($item:item)*) => {
$(
#[cfg(feature = "time")]
$item
)*
};
}
use core::future::Future;
cfg_time_with_docsrs!(
pub mod time;
);
#[macro_export]
macro_rules! cfg_tokio {
($($item:item)*) => {
$(
#[cfg(feature = "tokio")]
#[cfg_attr(docsrs, doc(cfg(feature = "tokio")))]
$item
)*
};
(@no_doc_cfg $($item:item)*) => {
$(
#[cfg(feature = "tokio")]
$item
)*
};
}
#[macro_export]
macro_rules! cfg_smol {
($($item:item)*) => {
$(
#[cfg(feature = "smol")]
#[cfg_attr(docsrs, doc(cfg(feature = "smol")))]
$item
)*
};
(@no_doc_cfg $($item:item)*) => {
$(
#[cfg(feature = "smol")]
$item
)*
};
}
#[macro_export]
macro_rules! cfg_unix {
($($item:item)*) => {
$(
#[cfg(feature = "unix")]
#[cfg_attr(docsrs, doc(cfg(feature = "unix")))]
$item
)*
};
(@no_doc_cfg $($item:item)*) => {
$(
#[cfg(feature = "unix")]
$item
)*
};
}
#[macro_export]
macro_rules! cfg_windows {
($($item:item)*) => {
$(
#[cfg(feature = "windows")]
#[cfg_attr(docsrs, doc(cfg(feature = "windows")))]
$item
)*
};
(@no_doc_cfg $($item:item)*) => {
$(
#[cfg(feature = "windows")]
$item
)*
};
}
#[macro_export]
macro_rules! cfg_linux {
($($item:item)*) => {
$(
#[cfg(target_os = "linux")]
#[cfg_attr(docsrs, doc(cfg(target_os = "linux")))]
$item
)*
};
(@no_doc_cfg $($item:item)*) => {
$(
#[cfg(target_os = "linux")]
$item
)*
};
}
#[macro_use]
mod spawner;
#[cfg(feature = "tokio")]
#[cfg_attr(docsrs, doc(cfg(feature = "tokio")))]
pub mod tokio;
#[cfg(feature = "smol")]
#[cfg_attr(docsrs, doc(cfg(feature = "smol")))]
pub mod smol;
#[cfg(feature = "wasm")]
#[cfg_attr(docsrs, doc(cfg(feature = "wasm")))]
pub mod wasm;
#[cfg(feature = "embassy")]
#[cfg_attr(docsrs, doc(cfg(feature = "embassy")))]
pub mod embassy;
#[cfg(feature = "async-io")]
#[cfg_attr(docsrs, doc(cfg(feature = "async-io")))]
pub mod async_io;
pub use spawner::*;
pub trait Yielder {
fn yield_now() -> impl Future<Output = ()> + Send;
fn yield_now_local() -> impl Future<Output = ()>;
}
pub trait RuntimeLite: Sized + Unpin + Copy + Send + Sync + 'static {
type Spawner: AsyncSpawner;
type LocalSpawner: AsyncLocalSpawner;
type BlockingSpawner: AsyncBlockingSpawner;
cfg_time_with_docsrs!(
type Instant: time::Instant;
type AfterSpawner: AsyncAfterSpawner<Instant = Self::Instant>;
type Interval: time::AsyncInterval<Instant = Self::Instant>;
type LocalInterval: time::AsyncLocalInterval<Instant = Self::Instant>;
type Sleep: time::AsyncSleep<Instant = Self::Instant>;
type LocalSleep: time::AsyncLocalSleep<Instant = Self::Instant>;
type Delay<F>: time::AsyncDelay<F, Instant = Self::Instant>
where
F: Future + Send;
type LocalDelay<F>: time::AsyncLocalDelay<F, Instant = Self::Instant>
where
F: Future;
type Timeout<F>: time::AsyncTimeout<F, Instant = Self::Instant>
where
F: Future + Send;
type LocalTimeout<F>: time::AsyncLocalTimeout<F, Instant = Self::Instant>
where
F: Future;
);
fn new() -> Self;
fn name() -> &'static str;
fn fqname() -> &'static str;
fn spawn<F>(future: F) -> <Self::Spawner as AsyncSpawner>::JoinHandle<F::Output>
where
F::Output: Send + 'static,
F: Future + Send + 'static,
{
<Self::Spawner as AsyncSpawner>::spawn(future)
}
fn spawn_detach<F>(future: F)
where
F::Output: Send + 'static,
F: Future + Send + 'static,
{
<Self::Spawner as AsyncSpawner>::spawn_detach(future);
}
fn spawn_local<F>(future: F) -> <Self::LocalSpawner as AsyncLocalSpawner>::JoinHandle<F::Output>
where
F: Future + 'static,
F::Output: 'static,
{
<Self::LocalSpawner as AsyncLocalSpawner>::spawn_local(future)
}
fn spawn_local_detach<F>(future: F)
where
F: Future + 'static,
F::Output: 'static,
{
<Self::LocalSpawner as AsyncLocalSpawner>::spawn_local_detach(future)
}
fn spawn_blocking<F, R>(f: F) -> <Self::BlockingSpawner as AsyncBlockingSpawner>::JoinHandle<R>
where
F: FnOnce() -> R + Send + 'static,
R: Send + 'static,
{
<Self::BlockingSpawner as AsyncBlockingSpawner>::spawn_blocking(f)
}
fn spawn_blocking_detach<F, R>(f: F)
where
F: FnOnce() -> R + Send + 'static,
R: Send + 'static,
{
<Self::BlockingSpawner as AsyncBlockingSpawner>::spawn_blocking_detach(f);
}
fn block_on<F: Future>(f: F) -> F::Output;
fn yield_now() -> impl Future<Output = ()> + Send;
cfg_time_with_docsrs!(
fn now() -> Self::Instant {
<Self::Instant as time::Instant>::now()
}
fn spawn_after<F>(
duration: core::time::Duration,
future: F,
) -> <Self::AfterSpawner as AsyncAfterSpawner>::JoinHandle<F::Output>
where
F::Output: Send + 'static,
F: Future + Send + 'static,
{
<Self::AfterSpawner as AsyncAfterSpawner>::spawn_after(duration, future)
}
fn spawn_after_at<F>(
at: Self::Instant,
future: F,
) -> <Self::AfterSpawner as AsyncAfterSpawner>::JoinHandle<F::Output>
where
F::Output: Send + 'static,
F: Future + Send + 'static,
{
<Self::AfterSpawner as AsyncAfterSpawner>::spawn_after_at(at, future)
}
fn interval(interval: core::time::Duration) -> Self::Interval;
fn interval_at(start: Self::Instant, period: core::time::Duration) -> Self::Interval;
fn interval_local(interval: core::time::Duration) -> Self::LocalInterval;
fn interval_local_at(start: Self::Instant, period: core::time::Duration)
-> Self::LocalInterval;
fn sleep(duration: core::time::Duration) -> Self::Sleep;
fn sleep_until(instant: Self::Instant) -> Self::Sleep;
fn sleep_local(duration: core::time::Duration) -> Self::LocalSleep;
fn sleep_local_until(instant: Self::Instant) -> Self::LocalSleep;
fn delay<F>(duration: core::time::Duration, fut: F) -> Self::Delay<F>
where
F: Future + Send;
fn delay_local<F>(duration: core::time::Duration, fut: F) -> Self::LocalDelay<F>
where
F: Future;
fn delay_at<F>(deadline: Self::Instant, fut: F) -> Self::Delay<F>
where
F: Future + Send;
fn delay_local_at<F>(deadline: Self::Instant, fut: F) -> Self::LocalDelay<F>
where
F: Future;
fn timeout<F>(duration: core::time::Duration, future: F) -> Self::Timeout<F>
where
F: Future + Send;
fn timeout_at<F>(deadline: Self::Instant, future: F) -> Self::Timeout<F>
where
F: Future + Send;
fn timeout_local<F>(duration: core::time::Duration, future: F) -> Self::LocalTimeout<F>
where
F: Future;
fn timeout_local_at<F>(deadline: Self::Instant, future: F) -> Self::LocalTimeout<F>
where
F: Future;
);
}
#[cfg(all(any(test, feature = "test"), feature = "std", feature = "time"))]
#[cfg_attr(docsrs, doc(cfg(all(any(test, feature = "test"), feature = "time"))))]
pub mod tests {
use core::sync::atomic::{AtomicUsize, Ordering};
use std::{sync::Arc, time::Duration};
use super::{AfterHandle, RuntimeLite};
pub async fn spawn_after_unittest<R: RuntimeLite>() {
let ctr = Arc::new(AtomicUsize::new(1));
let ctr1 = ctr.clone();
let handle = R::spawn_after(Duration::from_secs(1), async move {
ctr1.fetch_add(1, Ordering::SeqCst);
});
R::sleep(Duration::from_millis(500)).await;
assert_eq!(ctr.load(Ordering::SeqCst), 1);
handle.await.unwrap();
assert_eq!(ctr.load(Ordering::SeqCst), 2);
}
pub async fn spawn_after_cancel_unittest<R: RuntimeLite>() {
let ctr = Arc::new(AtomicUsize::new(1));
let ctr1 = ctr.clone();
let handle = R::spawn_after(Duration::from_secs(1), async move {
ctr1.fetch_add(1, Ordering::SeqCst);
});
R::sleep(Duration::from_millis(500)).await;
assert_eq!(ctr.load(Ordering::SeqCst), 1);
let o = handle.cancel().await;
assert!(o.is_none());
assert_eq!(ctr.load(Ordering::SeqCst), 1);
}
pub async fn spawn_after_drop_unittest<R: RuntimeLite>() {
let ctr = Arc::new(AtomicUsize::new(1));
let ctr1 = ctr.clone();
drop(R::spawn_after(Duration::from_secs(1), async move {
ctr1.fetch_add(1, Ordering::SeqCst);
}));
R::sleep(Duration::from_millis(500)).await;
assert_eq!(ctr.load(Ordering::SeqCst), 1);
R::sleep(Duration::from_millis(600)).await;
assert_eq!(ctr.load(Ordering::SeqCst), 2);
}
pub async fn spawn_after_abort_unittest<R: RuntimeLite>() {
let ctr = Arc::new(AtomicUsize::new(1));
let ctr1 = ctr.clone();
let handle = R::spawn_after(Duration::from_secs(1), async move {
ctr1.fetch_add(1, Ordering::SeqCst);
});
R::sleep(Duration::from_millis(500)).await;
assert_eq!(ctr.load(Ordering::SeqCst), 1);
handle.abort();
R::sleep(Duration::from_millis(600)).await;
assert_eq!(ctr.load(Ordering::SeqCst), 1);
}
pub async fn spawn_after_reset_to_pass_unittest<R: RuntimeLite>() {
let ctr = Arc::new(AtomicUsize::new(1));
let ctr1 = ctr.clone();
let handle = R::spawn_after(Duration::from_secs(1), async move {
ctr1.fetch_add(1, Ordering::SeqCst);
});
R::sleep(Duration::from_millis(500)).await;
assert_eq!(ctr.load(Ordering::SeqCst), 1);
handle.reset(Duration::from_millis(250));
R::sleep(Duration::from_millis(10)).await;
assert_eq!(ctr.load(Ordering::SeqCst), 2);
}
pub async fn spawn_after_reset_to_future_unittest<R: RuntimeLite>() {
let ctr = Arc::new(AtomicUsize::new(1));
let ctr1 = ctr.clone();
let handle = R::spawn_after(Duration::from_secs(1), async move {
ctr1.fetch_add(1, Ordering::SeqCst);
});
R::sleep(Duration::from_millis(500)).await;
assert_eq!(ctr.load(Ordering::SeqCst), 1);
handle.reset(Duration::from_millis(1250)); R::sleep(Duration::from_millis(750 + 10)).await; assert_eq!(ctr.load(Ordering::SeqCst), 2);
}
}