use std::fmt::Debug;
use std::fmt::Display;
use std::future::Future;
use std::io;
use std::time::Duration;
use openraft_macros::since;
use crate::Instant;
use crate::Mpsc;
use crate::MpscReceiver;
use crate::Mutex;
use crate::Oneshot;
use crate::OptionalSend;
use crate::OptionalSync;
use crate::TryRecvError;
use crate::Watch;
pub trait AsyncRuntime: Debug + OptionalSend + OptionalSync + 'static {
type JoinError: Debug + Display + OptionalSend;
type JoinHandle<T: OptionalSend + 'static>: Future<Output = Result<T, Self::JoinError>>
+ OptionalSend
+ OptionalSync
+ Unpin;
type Sleep: Future<Output = ()> + OptionalSend + OptionalSync;
type Instant: Instant;
type TimeoutError: Debug + Display + OptionalSend;
type Timeout<R, T: Future<Output = R> + OptionalSend>: Future<Output = Result<R, Self::TimeoutError>> + OptionalSend;
type ThreadLocalRng: rand::Rng;
#[track_caller]
fn spawn<T>(future: T) -> Self::JoinHandle<T::Output>
where
T: Future + OptionalSend + 'static,
T::Output: OptionalSend + 'static;
#[track_caller]
fn sleep(duration: Duration) -> Self::Sleep;
#[track_caller]
fn sleep_until(deadline: Self::Instant) -> Self::Sleep;
#[track_caller]
fn timeout<R, F: Future<Output = R> + OptionalSend>(duration: Duration, future: F) -> Self::Timeout<R, F>;
#[track_caller]
fn timeout_at<R, F: Future<Output = R> + OptionalSend>(deadline: Self::Instant, future: F) -> Self::Timeout<R, F>;
#[track_caller]
fn is_panic(join_error: &Self::JoinError) -> bool;
#[track_caller]
fn thread_rng() -> Self::ThreadLocalRng;
type Mpsc: Mpsc;
type Watch: Watch;
type Oneshot: Oneshot;
type Mutex<T: OptionalSend + 'static>: Mutex<T>;
fn new(threads: usize) -> Self;
fn block_on<F, T>(&mut self, future: F) -> T
where
F: Future<Output = T>,
T: OptionalSend;
fn run<F, T>(future: F) -> T
where
Self: Sized,
F: Future<Output = T>,
T: OptionalSend,
{
Self::new(8).block_on(future)
}
fn spawn_blocking<F, T>(f: F) -> impl Future<Output = Result<T, io::Error>> + Send
where
F: FnOnce() -> T + Send + 'static,
T: Send + 'static,
{
let (tx, rx) = futures_channel::oneshot::channel();
std::thread::spawn(move || {
tx.send(f()).ok();
});
async { rx.await.map_err(|_| io::Error::other("spawn_blocking task cancelled")) }
}
#[since(version = "0.10.0")]
fn mpsc_recv_deadline<T: OptionalSend>(
receiver: &mut <Self::Mpsc as Mpsc>::Receiver<T>,
deadline: Self::Instant,
) -> impl Future<Output = Result<T, TryRecvError>> + OptionalSend {
async move {
match receiver.try_recv() {
Ok(value) => Ok(value),
Err(TryRecvError::Disconnected) => Err(TryRecvError::Disconnected),
Err(TryRecvError::Empty) if <Self::Instant as Instant>::now() >= deadline => Err(TryRecvError::Empty),
Err(TryRecvError::Empty) => match Self::timeout_at(deadline, receiver.recv()).await {
Ok(None) => Err(TryRecvError::Disconnected),
Ok(Some(value)) => Ok(value),
Err(_) => Err(TryRecvError::Empty),
},
}
}
}
}