mirror of
https://github.com/lune-org/lune.git
synced 2025-05-04 10:43:57 +01:00
214 lines
5.3 KiB
Rust
214 lines
5.3 KiB
Rust
use std::{
|
|
future::Future,
|
|
io,
|
|
pin::Pin,
|
|
slice,
|
|
task::{Context, Poll},
|
|
time::{Duration, Instant},
|
|
};
|
|
|
|
use async_io::Timer;
|
|
use futures_lite::{prelude::*, ready};
|
|
use hyper::rt::{self, Executor, ReadBuf, ReadBufCursor};
|
|
use mlua::prelude::*;
|
|
use mlua_luau_scheduler::LuaSpawnExt;
|
|
|
|
// Hyper executor that spawns futures onto our Lua scheduler
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub struct HyperExecutor {
|
|
lua: Lua,
|
|
}
|
|
|
|
#[allow(dead_code)]
|
|
impl HyperExecutor {
|
|
pub fn execute<Fut>(lua: Lua, fut: Fut)
|
|
where
|
|
Fut: Future + Send + 'static,
|
|
Fut::Output: Send + 'static,
|
|
{
|
|
let exec = if let Some(exec) = lua.app_data_ref::<Self>() {
|
|
exec
|
|
} else {
|
|
lua.set_app_data(Self { lua: lua.clone() });
|
|
lua.app_data_ref::<Self>().unwrap()
|
|
};
|
|
|
|
exec.execute(fut);
|
|
}
|
|
}
|
|
|
|
impl<Fut: Future + Send + 'static> rt::Executor<Fut> for HyperExecutor
|
|
where
|
|
Fut::Output: Send + 'static,
|
|
{
|
|
fn execute(&self, fut: Fut) {
|
|
self.lua.spawn(fut).detach();
|
|
}
|
|
}
|
|
|
|
// Hyper timer & sleep future wrapper for async-io
|
|
|
|
#[derive(Debug)]
|
|
pub struct HyperTimer;
|
|
|
|
impl rt::Timer for HyperTimer {
|
|
fn sleep(&self, duration: Duration) -> Pin<Box<dyn rt::Sleep>> {
|
|
Box::pin(HyperSleep::from(Timer::after(duration)))
|
|
}
|
|
|
|
fn sleep_until(&self, at: Instant) -> Pin<Box<dyn rt::Sleep>> {
|
|
Box::pin(HyperSleep::from(Timer::at(at)))
|
|
}
|
|
|
|
fn reset(&self, sleep: &mut Pin<Box<dyn rt::Sleep>>, new_deadline: Instant) {
|
|
if let Some(mut sleep) = sleep.as_mut().downcast_mut_pin::<HyperSleep>() {
|
|
sleep.inner.set_at(new_deadline);
|
|
} else {
|
|
*sleep = Box::pin(HyperSleep::from(Timer::at(new_deadline)));
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub struct HyperSleep {
|
|
inner: Timer,
|
|
}
|
|
|
|
impl From<Timer> for HyperSleep {
|
|
fn from(inner: Timer) -> Self {
|
|
Self { inner }
|
|
}
|
|
}
|
|
|
|
impl Future for HyperSleep {
|
|
type Output = ();
|
|
|
|
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> {
|
|
match Pin::new(&mut self.inner).poll(cx) {
|
|
Poll::Ready(_) => Poll::Ready(()),
|
|
Poll::Pending => Poll::Pending,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl rt::Sleep for HyperSleep {}
|
|
|
|
// Hyper I/O wrapper for bidirectional compatibility
|
|
// between hyper & futures-lite async read/write traits
|
|
|
|
pin_project_lite::pin_project! {
|
|
#[derive(Debug)]
|
|
pub struct HyperIo<T> {
|
|
#[pin]
|
|
inner: T
|
|
}
|
|
}
|
|
|
|
impl<T> From<T> for HyperIo<T> {
|
|
fn from(inner: T) -> Self {
|
|
Self { inner }
|
|
}
|
|
}
|
|
|
|
impl<T> HyperIo<T> {
|
|
pub fn pin_mut(self: Pin<&mut Self>) -> Pin<&mut T> {
|
|
self.project().inner
|
|
}
|
|
}
|
|
|
|
// Compat for futures-lite -> hyper runtime
|
|
|
|
impl<T: AsyncRead> rt::Read for HyperIo<T> {
|
|
fn poll_read(
|
|
self: Pin<&mut Self>,
|
|
cx: &mut Context<'_>,
|
|
mut buf: ReadBufCursor<'_>,
|
|
) -> Poll<io::Result<()>> {
|
|
// Fill the read buffer with initialized data
|
|
let read_slice = unsafe {
|
|
let buffer = buf.as_mut();
|
|
buffer.as_mut_ptr().write_bytes(0, buffer.len());
|
|
slice::from_raw_parts_mut(buffer.as_mut_ptr().cast::<u8>(), buffer.len())
|
|
};
|
|
|
|
// Read bytes from the underlying source
|
|
let n = match self.pin_mut().poll_read(cx, read_slice) {
|
|
Poll::Ready(Ok(n)) => n,
|
|
Poll::Ready(Err(e)) => return Poll::Ready(Err(e)),
|
|
Poll::Pending => return Poll::Pending,
|
|
};
|
|
|
|
unsafe {
|
|
buf.advance(n);
|
|
}
|
|
|
|
Poll::Ready(Ok(()))
|
|
}
|
|
}
|
|
|
|
impl<T: AsyncWrite> rt::Write for HyperIo<T> {
|
|
fn poll_write(
|
|
self: Pin<&mut Self>,
|
|
cx: &mut Context<'_>,
|
|
buf: &[u8],
|
|
) -> Poll<io::Result<usize>> {
|
|
self.pin_mut().poll_write(cx, buf)
|
|
}
|
|
|
|
fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
|
|
self.pin_mut().poll_flush(cx)
|
|
}
|
|
|
|
fn poll_shutdown(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
|
|
self.pin_mut().poll_close(cx)
|
|
}
|
|
|
|
fn poll_write_vectored(
|
|
self: Pin<&mut Self>,
|
|
cx: &mut Context<'_>,
|
|
bufs: &[io::IoSlice<'_>],
|
|
) -> Poll<io::Result<usize>> {
|
|
self.pin_mut().poll_write_vectored(cx, bufs)
|
|
}
|
|
}
|
|
|
|
// Compat for hyper runtime -> futures-lite
|
|
|
|
impl<T: rt::Read> AsyncRead for HyperIo<T> {
|
|
fn poll_read(
|
|
self: Pin<&mut Self>,
|
|
cx: &mut Context<'_>,
|
|
buf: &mut [u8],
|
|
) -> Poll<io::Result<usize>> {
|
|
let mut buf = ReadBuf::new(buf);
|
|
ready!(self.pin_mut().poll_read(cx, buf.unfilled()))?;
|
|
Poll::Ready(Ok(buf.filled().len()))
|
|
}
|
|
}
|
|
|
|
impl<T: rt::Write> AsyncWrite for HyperIo<T> {
|
|
fn poll_write(
|
|
self: Pin<&mut Self>,
|
|
cx: &mut Context<'_>,
|
|
buf: &[u8],
|
|
) -> Poll<Result<usize, std::io::Error>> {
|
|
self.pin_mut().poll_write(cx, buf)
|
|
}
|
|
|
|
fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), std::io::Error>> {
|
|
self.pin_mut().poll_flush(cx)
|
|
}
|
|
|
|
fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
|
|
self.pin_mut().poll_shutdown(cx)
|
|
}
|
|
|
|
fn poll_write_vectored(
|
|
self: Pin<&mut Self>,
|
|
cx: &mut Context<'_>,
|
|
bufs: &[std::io::IoSlice<'_>],
|
|
) -> Poll<Result<usize, std::io::Error>> {
|
|
self.pin_mut().poll_write_vectored(cx, bufs)
|
|
}
|
|
}
|