use std::future::Future;
use std::io;
use std::pin::Pin;
pub trait AsyncRead {
fn read<'a>(
&'a mut self,
buf: &'a mut [u8],
) -> Pin<Box<dyn Future<Output = io::Result<usize>> + Send + 'a>>;
}
pub async fn read_exact<T: AsyncRead + Unpin + ?Sized>(
reader: &mut T,
mut buf: &mut [u8],
) -> io::Result<()> {
while !buf.is_empty() {
match reader.read(buf).await {
Ok(0) => {
return Err(io::Error::new(
io::ErrorKind::UnexpectedEof,
"failed to fill buffer",
));
}
Ok(n) => buf = &mut buf[n..],
Err(e) => return Err(e),
}
}
Ok(())
}
pub trait AsyncWrite {
fn write<'a>(
&'a mut self,
buf: &'a [u8],
) -> Pin<Box<dyn Future<Output = io::Result<usize>> + Send + 'a>>;
fn flush<'a>(&'a mut self) -> Pin<Box<dyn Future<Output = io::Result<()>> + Send + 'a>>;
}
pub async fn write_all<T: AsyncWrite + Unpin + ?Sized>(
writer: &mut T,
mut buf: &[u8],
) -> io::Result<()> {
while !buf.is_empty() {
match writer.write(buf).await {
Ok(0) => {
return Err(io::Error::new(
io::ErrorKind::WriteZero,
"failed to write whole buffer",
));
}
Ok(n) => buf = &buf[n..],
Err(e) => return Err(e),
}
}
writer.flush().await
}
pub mod ipc_utils {
use super::*;
pub async fn read_u32_le<T: AsyncRead + Unpin>(reader: &mut T) -> io::Result<u32> {
let mut buffer = [0u8; 4];
super::read_exact(reader, &mut buffer).await?;
Ok(u32::from_le_bytes(buffer))
}
#[allow(dead_code)]
pub async fn write_u32_le<T: AsyncWrite + Unpin>(writer: &mut T, value: u32) -> io::Result<()> {
super::write_all(writer, &value.to_le_bytes()).await
}
#[allow(dead_code)]
pub async fn read_header<T: AsyncRead + Unpin>(reader: &mut T) -> io::Result<(u32, u32)> {
let opcode = read_u32_le(reader).await?;
let length = read_u32_le(reader).await?;
Ok((opcode, length))
}
}