use anyhow::Context as _;
use byteorder::ByteOrder;
use byteorder::NativeEndian;
use crate::de::read::DeRead;
use crate::de::read::Reference;
use crate::errors::*;
use crate::header::*;
#[derive(Debug)]
pub struct Bunser<R> {
read: R,
scratch: Vec<u8>,
}
pub struct PduInfo {
pub bser_capabilities: u32,
pub len: i64,
pub start: i64,
}
impl<'de, R> Bunser<R>
where
R: DeRead<'de>,
{
pub fn new(read: R) -> Self {
Bunser {
read,
scratch: Vec::with_capacity(128),
}
}
pub fn read_pdu(&mut self) -> Result<PduInfo> {
{
let magic = self.read_bytes(2)?;
if magic.get_ref() != &EMPTY_HEADER[..2] {
return Err(Error::DeInvalidMagic {
magic: Vec::from(magic.get_ref()),
});
}
}
let bser_capabilities = self
.read
.next_u32(&mut self.scratch)
.map_err(Error::de_reader_error)?;
let len = self.check_next_int()?;
let start = self.read_count();
Ok(PduInfo {
bser_capabilities,
len,
start,
})
}
pub fn read_count(&self) -> i64 {
self.read.read_count() as i64
}
pub fn end(&self, pdu_info: &PduInfo) -> Result<()> {
let expected = (pdu_info.start + pdu_info.len) as usize;
if self.read.read_count() != expected {
return Err(Error::DeEof {
expected,
read: self.read.read_count(),
});
}
Ok(())
}
#[inline]
pub fn peek(&mut self) -> Result<u8> {
self.read.peek().map_err(Error::de_reader_error)
}
#[inline]
pub fn discard(&mut self) {
self.read.discard();
}
#[inline]
pub fn read_bytes<'s>(&'s mut self, len: i64) -> Result<Reference<'de, 's, [u8]>> {
let len = len as usize;
self.read
.next_bytes(len, &mut self.scratch)
.map_err(Error::de_reader_error)
}
pub fn next_i8(&mut self) -> Result<i8> {
self.read.discard();
let bytes = self
.read_bytes(1)
.context("error while reading i8")
.map_err(Error::de_reader_error)?
.get_ref();
Ok(bytes[0] as i8)
}
pub fn next_i16(&mut self) -> Result<i16> {
self.read.discard();
let bytes = self
.read_bytes(2)
.context("error while reading i16")
.map_err(Error::de_reader_error)?
.get_ref();
Ok(NativeEndian::read_i16(bytes))
}
pub fn next_i32(&mut self) -> Result<i32> {
self.read.discard();
let bytes = self
.read_bytes(4)
.context("error while reading i32")
.map_err(Error::de_reader_error)?
.get_ref();
Ok(NativeEndian::read_i32(bytes))
}
pub fn next_i64(&mut self) -> Result<i64> {
self.read.discard();
let bytes = self
.read_bytes(8)
.context("error while reading i64")
.map_err(Error::de_reader_error)?
.get_ref();
Ok(NativeEndian::read_i64(bytes))
}
pub fn check_next_int(&mut self) -> Result<i64> {
let value = match self.peek()? {
BSER_INT8 => self.next_i8()? as i64,
BSER_INT16 => self.next_i16()? as i64,
BSER_INT32 => self.next_i32()? as i64,
BSER_INT64 => self.next_i64()?,
ch => {
return Err(Error::DeInvalidStartByte {
kind: "integer".into(),
byte: ch,
});
}
};
Ok(value)
}
pub fn next_f64(&mut self) -> Result<f64> {
self.read.discard();
let bytes = self
.read_bytes(8)
.context("error while reading f64")
.map_err(Error::de_reader_error)?
.get_ref();
Ok(NativeEndian::read_f64(bytes))
}
}