use std::ffi::c_void;
use std::pin::Pin;
use std::task::{Context, Poll};
use libc::size_t;
use tokio::io::{AsyncRead, AsyncWrite};
use super::task::hyper_context;
pub const HYPER_IO_PENDING: size_t = 0xFFFFFFFF;
pub const HYPER_IO_ERROR: size_t = 0xFFFFFFFE;
type hyper_io_read_callback =
extern "C" fn(*mut c_void, *mut hyper_context<'_>, *mut u8, size_t) -> size_t;
type hyper_io_write_callback =
extern "C" fn(*mut c_void, *mut hyper_context<'_>, *const u8, size_t) -> size_t;
pub struct Io {
read: hyper_io_read_callback,
write: hyper_io_write_callback,
userdata: *mut c_void,
}
ffi_fn! {
fn hyper_io_new() -> *mut Io {
Box::into_raw(Box::new(Io {
read: read_noop,
write: write_noop,
userdata: std::ptr::null_mut(),
}))
}
}
ffi_fn! {
fn hyper_io_free(io: *mut Io) {
drop(unsafe { Box::from_raw(io) });
}
}
ffi_fn! {
fn hyper_io_set_userdata(io: *mut Io, data: *mut c_void) {
unsafe { &mut *io }.userdata = data;
}
}
ffi_fn! {
fn hyper_io_set_read(io: *mut Io, func: hyper_io_read_callback) {
unsafe { &mut *io }.read = func;
}
}
ffi_fn! {
fn hyper_io_set_write(io: *mut Io, func: hyper_io_write_callback) {
unsafe { &mut *io }.write = func;
}
}
extern "C" fn read_noop(
_userdata: *mut c_void,
_: *mut hyper_context<'_>,
_buf: *mut u8,
_buf_len: size_t,
) -> size_t {
0
}
extern "C" fn write_noop(
_userdata: *mut c_void,
_: *mut hyper_context<'_>,
_buf: *const u8,
_buf_len: size_t,
) -> size_t {
0
}
impl AsyncRead for Io {
fn poll_read(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &mut tokio::io::ReadBuf<'_>,
) -> Poll<std::io::Result<()>> {
let buf_ptr = unsafe { buf.unfilled_mut() }.as_mut_ptr() as *mut u8;
let buf_len = buf.remaining();
match (self.read)(self.userdata, hyper_context::wrap(cx), buf_ptr, buf_len) {
HYPER_IO_PENDING => Poll::Pending,
HYPER_IO_ERROR => Poll::Ready(Err(std::io::Error::new(
std::io::ErrorKind::Other,
"io error",
))),
ok => {
unsafe { buf.assume_init(ok) };
buf.advance(ok);
Poll::Ready(Ok(()))
}
}
}
}
impl AsyncWrite for Io {
fn poll_write(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &[u8],
) -> Poll<std::io::Result<usize>> {
let buf_ptr = buf.as_ptr();
let buf_len = buf.len();
match (self.write)(self.userdata, hyper_context::wrap(cx), buf_ptr, buf_len) {
HYPER_IO_PENDING => Poll::Pending,
HYPER_IO_ERROR => Poll::Ready(Err(std::io::Error::new(
std::io::ErrorKind::Other,
"io error",
))),
ok => Poll::Ready(Ok(ok)),
}
}
fn poll_flush(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<std::io::Result<()>> {
Poll::Ready(Ok(()))
}
fn poll_shutdown(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<std::io::Result<()>> {
Poll::Ready(Ok(()))
}
}
unsafe impl Send for Io {}
unsafe impl Sync for Io {}