use half::f16;
use std::io;
use crate::byteorder_io::ByteOrder;
use crate::multifilereader::HasError;
use crate::peekreader::PeekRead;
pub struct InputDecoder<'a, I>
where
I: 'a,
{
input: &'a mut I,
data: Vec<u8>,
reserved_peek_length: usize,
used_normal_length: usize,
used_peek_length: usize,
byte_order: ByteOrder,
}
impl<'a, I> InputDecoder<'a, I> {
pub fn new(
input: &mut I,
normal_length: usize,
peek_length: usize,
byte_order: ByteOrder,
) -> InputDecoder<I> {
let bytes = vec![0; normal_length + peek_length];
InputDecoder {
input,
data: bytes,
reserved_peek_length: peek_length,
used_normal_length: 0,
used_peek_length: 0,
byte_order,
}
}
}
impl<'a, I> InputDecoder<'a, I>
where
I: PeekRead,
{
pub fn peek_read(&mut self) -> io::Result<MemoryDecoder> {
match self
.input
.peek_read(self.data.as_mut_slice(), self.reserved_peek_length)
{
Ok((n, p)) => {
self.used_normal_length = n;
self.used_peek_length = p;
Ok(MemoryDecoder {
data: &mut self.data,
used_normal_length: self.used_normal_length,
used_peek_length: self.used_peek_length,
byte_order: self.byte_order,
})
}
Err(e) => Err(e),
}
}
}
impl<'a, I> HasError for InputDecoder<'a, I>
where
I: HasError,
{
fn has_error(&self) -> bool {
self.input.has_error()
}
}
pub struct MemoryDecoder<'a> {
data: &'a mut Vec<u8>,
used_normal_length: usize,
used_peek_length: usize,
byte_order: ByteOrder,
}
impl<'a> MemoryDecoder<'a> {
pub fn zero_out_buffer(&mut self, start: usize, end: usize) {
for i in start..end {
self.data[i] = 0;
}
}
pub fn length(&self) -> usize {
self.used_normal_length
}
pub fn clone_buffer(&self, other: &mut Vec<u8>) {
other.clone_from(self.data);
other.resize(self.used_normal_length, 0);
}
pub fn get_buffer(&self, start: usize) -> &[u8] {
&self.data[start..self.used_normal_length]
}
pub fn get_full_buffer(&self, start: usize) -> &[u8] {
&self.data[start..self.used_normal_length + self.used_peek_length]
}
pub fn read_uint(&self, start: usize, byte_size: usize) -> u64 {
match byte_size {
1 => u64::from(self.data[start]),
2 => u64::from(self.byte_order.read_u16(&self.data[start..start + 2])),
4 => u64::from(self.byte_order.read_u32(&self.data[start..start + 4])),
8 => self.byte_order.read_u64(&self.data[start..start + 8]),
_ => panic!("Invalid byte_size: {}", byte_size),
}
}
pub fn read_float(&self, start: usize, byte_size: usize) -> f64 {
match byte_size {
2 => f64::from(f16::from_bits(
self.byte_order.read_u16(&self.data[start..start + 2]),
)),
4 => f64::from(self.byte_order.read_f32(&self.data[start..start + 4])),
8 => self.byte_order.read_f64(&self.data[start..start + 8]),
_ => panic!("Invalid byte_size: {}", byte_size),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::byteorder_io::ByteOrder;
use crate::peekreader::PeekReader;
use std::io::Cursor;
#[test]
#[allow(clippy::float_cmp)]
fn smoke_test() {
let data = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xff, 0xff];
let mut input = PeekReader::new(Cursor::new(&data));
let mut sut = InputDecoder::new(&mut input, 8, 2, ByteOrder::Little);
let mut mem = sut.peek_read().unwrap();
assert_eq!(8, mem.length());
assert_eq!(-2.0, mem.read_float(0, 8));
assert_eq!(-2.0, mem.read_float(4, 4));
assert_eq!(0xc000000000000000, mem.read_uint(0, 8));
assert_eq!(0xc0000000, mem.read_uint(4, 4));
assert_eq!(0xc000, mem.read_uint(6, 2));
assert_eq!(0xc0, mem.read_uint(7, 1));
assert_eq!(&[0, 0xc0], mem.get_buffer(6));
assert_eq!(&[0, 0xc0, 0xff, 0xff], mem.get_full_buffer(6));
let mut copy: Vec<u8> = Vec::new();
mem.clone_buffer(&mut copy);
assert_eq!(vec![0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0], copy);
mem.zero_out_buffer(7, 8);
assert_eq!(&[0, 0, 0xff, 0xff], mem.get_full_buffer(6));
let mem = sut.peek_read().unwrap();
assert_eq!(2, mem.length());
assert_eq!(0xffff, mem.read_uint(0, 2));
}
}