use crate::{chunk::Chunk, Result};
use byteorder::{BigEndian, ByteOrder};
use tokio::io::{AsyncRead, AsyncReadExt};
pub struct AsyncReader<'r, const L: usize, T: AsyncRead + Unpin>(Chunk<L>, &'r mut T);
impl<'r, const L: usize, T: 'r + AsyncRead + Unpin> AsyncReader<'r, L, T> {
pub fn new(reader: &'r mut T) -> Self {
Self(Chunk::alloc(), reader)
}
pub async fn read_to_fill(&mut self) -> Result<()> {
(&mut self.0).fill_from_reader(&mut self.1).await?;
Ok(())
}
pub async fn fill_inplace(mut self) -> Result<AsyncReader<'r, L, T>> {
(&mut self).read_to_fill().await?;
Ok(self)
}
pub fn consume_with_state<const S: usize>(&mut self, cursor: &mut usize) -> [u8; S] {
assert!(*cursor < L);
let mut buf: [u8; S] = [0; S];
buf.copy_from_slice(&mut self.0 .0[*cursor..(*cursor + S)]);
*cursor += S;
buf
}
pub fn consume<const S: usize>(mut self) -> [u8; S] {
self.consume_with_state(&mut 0)
}
pub async fn read(&mut self) -> Result<usize> {
(&mut self.0).read_from_reader(&mut self.1).await?;
Ok(self.0 .1) }
pub async fn read_to_chunk(reader: &'r mut T) -> Result<Chunk<L>> {
let mut reader = Self(Chunk::alloc(), reader);
reader.read_to_fill().await?;
Ok(reader.0)
}
}
pub struct AsyncVecReader<'r, T: AsyncRead + Unpin>(Vec<u8>, &'r mut T);
impl<'r, T: 'r + AsyncRead + Unpin> AsyncVecReader<'r, T> {
pub fn new(target_size: usize, reader: &'r mut T) -> Self {
Self(vec![0; target_size], reader)
}
pub async fn read_to_vec(mut self) -> Result<Vec<u8>> {
self.1.read_exact(&mut self.0).await?;
Ok(self.0)
}
}
pub struct LengthReader<'r, T: 'r + AsyncRead + Unpin>(AsyncReader<'r, 4, T>);
impl<'r, T: 'r + AsyncRead + Unpin> LengthReader<'r, T> {
pub fn new(r: &'r mut T) -> Self {
Self(AsyncReader(Chunk::alloc(), r))
}
pub async fn read_u32(self) -> Result<u32> {
Ok(BigEndian::read_u32(
self.0.fill_inplace().await?.consume::<4>().as_slice(),
))
}
}