use anyhow::Result;
use core::{
cell::RefCell,
cmp::Ordering,
future::Future,
pin::Pin,
task::{Context, Poll},
};
use kona_common::{io, FileDescriptor};
#[derive(Debug, Clone, Copy)]
pub struct PipeHandle {
read_handle: FileDescriptor,
write_handle: FileDescriptor,
}
impl PipeHandle {
pub const fn new(read_handle: FileDescriptor, write_handle: FileDescriptor) -> Self {
Self { read_handle, write_handle }
}
pub fn read(&self, buf: &mut [u8]) -> Result<usize> {
io::read(self.read_handle, buf)
}
pub fn read_exact<'a>(&self, buf: &'a mut [u8]) -> impl Future<Output = Result<usize>> + 'a {
ReadFuture { pipe_handle: *self, buf: RefCell::new(buf), read: 0 }
}
pub fn write<'a>(&self, buf: &'a [u8]) -> impl Future<Output = Result<usize>> + 'a {
WriteFuture { pipe_handle: *self, buf, written: 0 }
}
pub fn read_handle(&self) -> FileDescriptor {
self.read_handle
}
pub fn write_handle(&self) -> FileDescriptor {
self.write_handle
}
}
struct ReadFuture<'a> {
pipe_handle: PipeHandle,
buf: RefCell<&'a mut [u8]>,
read: usize,
}
impl Future for ReadFuture<'_> {
type Output = Result<usize>;
fn poll(mut self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<Self::Output> {
let mut buf = self.buf.borrow_mut();
let buf_len = buf.len();
let chunk_read = self.pipe_handle.read(&mut buf[self.read..])?;
drop(buf);
self.read += chunk_read;
match self.read.cmp(&buf_len) {
Ordering::Greater | Ordering::Equal => Poll::Ready(Ok(self.read)),
Ordering::Less => {
ctx.waker().wake_by_ref();
Poll::Pending
}
}
}
}
struct WriteFuture<'a> {
pipe_handle: PipeHandle,
buf: &'a [u8],
written: usize,
}
impl Future for WriteFuture<'_> {
type Output = Result<usize>;
fn poll(mut self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<Self::Output> {
match io::write(self.pipe_handle.write_handle(), &self.buf[self.written..]) {
Ok(0) => Poll::Ready(Ok(self.written)), Ok(n) => {
self.written += n;
if self.written >= self.buf.len() {
return Poll::Ready(Ok(self.written));
}
ctx.waker().wake_by_ref();
Poll::Pending
}
Err(e) => Poll::Ready(Err(e)),
}
}
}