binprot 0.1.7

Rust implementation of the bin_prot protocol.
Documentation
use crate::error::Error;
use crate::int::{CODE_INT16, CODE_INT32, CODE_INT64, CODE_NEG_INT8};
use crate::{BinProtRead, BinProtWrite};
use tokio::io::{AsyncReadExt, AsyncWriteExt};

pub struct AsyncBuffer(Vec<u8>);

impl AsyncBuffer {
    pub fn new(buf_size: usize) -> Self {
        AsyncBuffer(Vec::with_capacity(buf_size))
    }

    pub async fn read_with_size<T: BinProtRead, R: AsyncReadExt + Unpin>(
        &mut self,
        r: &mut R,
    ) -> Result<T, Error> {
        let buf = &mut self.0;
        let mut recv_bytes = [0u8; 8];
        r.read_exact(&mut recv_bytes).await?;
        let recv_len = i64::from_le_bytes(recv_bytes);
        buf.resize(recv_len as usize, 0u8);
        r.read_exact(buf).await?;
        let data = T::binprot_read(&mut buf.as_slice())?;
        Ok(data)
    }

    pub async fn write_with_size<T: BinProtWrite, W: AsyncWriteExt + Unpin>(
        &mut self,
        w: &mut W,
        v: &T,
    ) -> std::io::Result<()> {
        let buf = &mut self.0;
        buf.clear();
        v.binprot_write(buf)?;
        let len = buf.len() as i64;
        w.write_all(&len.to_le_bytes()).await?;
        w.write_all(buf).await?;
        Ok(())
    }
}

pub async fn write_nat0<W: AsyncWriteExt + Unpin>(w: &mut W, v: u64) -> std::io::Result<()> {
    if v < 0x000000080 {
        w.write_all(&[v as u8]).await?;
    } else if v < 0x000010000 {
        w.write_all(&[CODE_INT16]).await?;
        w.write_all(&(v as u16).to_le_bytes()).await?;
    } else if v < 0x100000000 {
        w.write_all(&[CODE_INT32]).await?;
        w.write_all(&(v as u32).to_le_bytes()).await?;
    } else {
        w.write_all(&[CODE_INT64]).await?;
        w.write_all(&v.to_le_bytes()).await?;
    }
    Ok(())
}

pub async fn write_i64<W: AsyncWriteExt + Unpin>(w: &mut W, v: i64) -> std::io::Result<()> {
    if 0 <= v {
        if v < 0x000000080 {
            w.write_all(&[v as u8]).await?;
        } else if v < 0x00008000 {
            w.write_all(&[CODE_INT16]).await?;
            w.write_all(&(v as u16).to_le_bytes()).await?;
        } else if v < 0x80000000 {
            w.write_all(&[CODE_INT32]).await?;
            w.write_all(&(v as u32).to_le_bytes()).await?;
        } else {
            w.write_all(&[CODE_INT64]).await?;
            w.write_all(&v.to_le_bytes()).await?;
        }
    } else if v >= -0x00000080 {
        w.write_all(&[CODE_NEG_INT8]).await?;
        w.write_all(&v.to_le_bytes()[..1]).await?;
    } else if v >= -0x00008000 {
        w.write_all(&[CODE_INT16]).await?;
        w.write_all(&v.to_le_bytes()[..2]).await?;
    } else if v >= -0x80000000 {
        w.write_all(&[CODE_INT32]).await?;
        w.write_all(&v.to_le_bytes()[..4]).await?;
    } else if v < -0x80000000 {
        w.write_all(&[CODE_INT64]).await?;
        w.write_all(&v.to_le_bytes()).await?;
    }
    Ok(())
}

pub async fn read_signed<R: AsyncReadExt + Unpin + ?Sized>(r: &mut R) -> std::io::Result<i64> {
    let c = r.read_u8().await?;
    let v = match c {
        CODE_NEG_INT8 => r.read_i8().await? as i64,
        CODE_INT16 => r.read_i16().await? as i64,
        CODE_INT32 => r.read_i32().await? as i64,
        CODE_INT64 => r.read_i64().await?,
        c => c as i64,
    };
    Ok(v)
}

pub async fn read_nat0<R: AsyncReadExt + Unpin + ?Sized>(r: &mut R) -> std::io::Result<u64> {
    let c = r.read_u8().await?;
    let v = match c {
        CODE_INT16 => r.read_u16().await? as u64,
        CODE_INT32 => r.read_u32().await? as u64,
        CODE_INT64 => r.read_u64().await?,
        c => c as u64,
    };
    Ok(v)
}