use futures_lite::{Stream, future};
use std::{future::Future, sync::Arc, thread, time::Duration};
use trillium_server_common::{DroppableFuture, Runtime, RuntimeTrait};
#[derive(Debug, Clone, Copy, Default)]
pub struct RuntimelessRuntime(());
impl RuntimeTrait for RuntimelessRuntime {
fn spawn<Fut>(
&self,
fut: Fut,
) -> DroppableFuture<impl Future<Output = Option<Fut::Output>> + Send + 'static>
where
Fut: Future + Send + 'static,
Fut::Output: Send + 'static,
{
let rt = *self;
let (send, receive) = async_channel::bounded(1);
thread::spawn(move || {
let _ = send.send_blocking(rt.block_on(fut));
});
DroppableFuture::new(async move { receive.recv().await.ok() })
}
async fn delay(&self, duration: Duration) {
let (send, receive) = async_channel::bounded(1);
thread::spawn(move || {
thread::sleep(duration);
let _ = send.send_blocking(());
});
let _ = receive.recv().await;
}
fn interval(&self, period: Duration) -> impl Stream<Item = ()> + Send + 'static {
let (send, receive) = async_channel::bounded(1);
thread::spawn(move || {
loop {
thread::sleep(period);
if send.send_blocking(()).is_err() {
break;
}
}
});
receive
}
fn block_on<Fut: Future>(&self, fut: Fut) -> Fut::Output {
future::block_on(fut)
}
}
impl From<RuntimelessRuntime> for Runtime {
fn from(value: RuntimelessRuntime) -> Self {
Arc::new(value).into()
}
}
impl RuntimelessRuntime {
pub fn spawn<Fut>(
&self,
fut: Fut,
) -> DroppableFuture<impl Future<Output = Option<Fut::Output>> + Send + 'static + use<Fut>>
where
Fut: Future + Send + 'static,
Fut::Output: Send + 'static,
{
let rt = *self;
let (send, receive) = async_channel::bounded(1);
thread::spawn(move || {
let _ = send.send_blocking(rt.block_on(fut));
});
DroppableFuture::new(async move { receive.recv().await.ok() })
}
pub async fn delay(&self, duration: Duration) {
RuntimeTrait::delay(self, duration).await
}
pub fn interval(&self, period: Duration) -> impl Stream<Item = ()> + Send + 'static + use<> {
let (send, receive) = async_channel::bounded(1);
thread::spawn(move || {
loop {
thread::sleep(period);
if send.is_closed() {
break;
}
let _ = send.send_blocking(());
}
});
receive
}
pub fn block_on<Fut: Future>(&self, fut: Fut) -> Fut::Output {
future::block_on(fut)
}
pub async fn timeout<Fut>(&self, duration: Duration, fut: Fut) -> Option<Fut::Output>
where
Fut: Future + Send,
Fut::Output: Send + 'static,
{
RuntimeTrait::timeout(self, duration, fut).await
}
}