use crate::raw::{Dehydrate, Hydrate, R, RError, T, TError};
use std::{io::Cursor, pin::Pin};
use tokio::io::{AsyncReadExt, AsyncWriteExt};
pub type AsyncRead = Pin<Box<dyn tokio::io::AsyncRead + Send>>;
pub type AsyncWrite = Pin<Box<dyn tokio::io::AsyncWrite + Send>>;
macro_rules! async_reader {
($name:ident -> <$ty:ty, $err:ty>, $overlong:expr) => {
pub struct $name(AsyncRead, u32);
unsafe impl Send for $name {}
impl $name {
pub fn new(r: AsyncRead, msize: u32) -> Self {
Self(r, msize)
}
pub fn set_msize(&mut self, msize: u32) {
self.1 = msize;
}
pub async fn next(&mut self) -> Result<$ty, $err> {
let mut size = [0, 0, 0, 0];
self.0.read_exact(&mut size).await?;
let size = u32::from_le_bytes(size);
if size > self.1 {
return Err($overlong);
}
let size = size as usize;
let mut buf = vec![0u8; size - 4];
self.0.read_exact(&mut buf).await?;
let mut c = Cursor::new(buf);
<$ty>::hydrate(&mut c)
}
}
};
}
macro_rules! async_writer {
($name:ident -> <$ty:ty, $err:ty>, $overlong:expr) => {
pub struct $name(AsyncWrite, u32);
unsafe impl Send for $name {}
impl $name {
pub fn new(w: AsyncWrite, msize: u32) -> Self {
Self(w, msize)
}
pub fn set_msize(&mut self, msize: u32) {
self.1 = msize;
}
pub async fn send(&mut self, msg: $ty) -> Result<(), $err> {
let mut buf = Cursor::new(vec![0; self.1 as usize]);
msg.dehydrate(&mut buf)?;
let pos = buf.position() as usize;
let size = pos + 4;
if size > (self.1 as usize) {
return Err($overlong);
}
self.0.write_all(&(size as u32).to_le_bytes()).await?;
let buf = buf.into_inner();
self.0.write_all(&buf[..pos]).await?;
Ok(())
}
}
};
}
async_reader!(RReader -> <R, RError>, RError::TooLong);
async_reader!(TReader -> <T, TError>, TError::TooLong);
async_writer!(RWriter -> <R, RError>, RError::TooLong);
async_writer!(TWriter -> <T, TError>, TError::TooLong);