use std::io::{Read, Write};
use crate::error::{Error, Result};
use crate::{ULEB128_U32_MAX_LENGTH, ULEB128_U64_MAX_LENGTH};
const VALUE_MASK: u8 = 0b0111_1111;
const VALUE_LENGTH: usize = 7;
macro_rules! read_method_body {
($self:expr, $ty:ty, $len:expr) => {{
let mut value = 0;
let mut bytes_read = 0;
loop {
let mut buf = [0; 1];
$self.read_exact(&mut buf)?;
let byte = buf[0];
let byte_value = (byte & VALUE_MASK) as $ty;
value |= byte_value << (VALUE_LENGTH * bytes_read);
bytes_read += 1;
if bytes_read > $len {
return Err(Error::LengthOverflow($len));
}
if (byte & !VALUE_MASK) == 0 {
break;
}
}
Ok(value)
}};
}
pub trait ReadULeb128Ext: Read {
fn read_uleb128_u32(&mut self) -> Result<u32> {
read_method_body!(self, u32, ULEB128_U32_MAX_LENGTH)
}
fn read_uleb128_u64(&mut self) -> Result<u64> {
read_method_body!(self, u64, ULEB128_U64_MAX_LENGTH)
}
}
impl<R: Read + ?Sized> ReadULeb128Ext for R {}
macro_rules! write_method_body {
($self:expr, $value:ident, $ty:ty) => {{
let mut value = $value;
loop {
let mut byte = value & VALUE_MASK as $ty;
value >>= VALUE_LENGTH;
if value != 0 {
byte |= !VALUE_MASK as $ty;
}
$self.write_all(&[byte as u8])?;
if value == 0 {
return Ok(());
}
}
}};
}
pub trait WriteULeb128Ext: Write {
fn write_uleb128_u32(&mut self, value: u32) -> Result {
write_method_body!(self, value, u32)
}
fn write_uleb128_u64(&mut self, value: u64) -> Result {
write_method_body!(self, value, u64)
}
}
impl<W: Write + ?Sized> WriteULeb128Ext for W {}