use std;
use std::io::{self, Cursor, ErrorKind, Read};
use std::str;
use rmp::decode::{read_marker, RmpRead};
use rmp::Marker;
use super::Error;
use crate::{Utf8StringRef, ValueRef};
fn read_str_data<'a, R>(rd: &mut R, len: usize, depth: u16) -> Result<Utf8StringRef<'a>, Error>
where R: BorrowRead<'a>
{
let depth = super::decrement_depth(depth)?;
let buf = read_bin_data(rd, len, depth)?;
match str::from_utf8(buf) {
Ok(s) => Ok(Utf8StringRef::from(s)),
Err(err) => {
let s = Utf8StringRef {
s: Err((buf, err)),
};
Ok(s)
}
}
}
fn read_bin_data<'a, R>(rd: &mut R, len: usize, depth: u16) -> Result<&'a [u8], Error>
where R: BorrowRead<'a>
{
let _depth = super::decrement_depth(depth)?;
let buf = rd.fill_buf();
if len > buf.len() {
return Err(Error::InvalidDataRead(io::Error::new(ErrorKind::UnexpectedEof, "unexpected EOF")));
}
let buf = &buf[..len];
rd.consume(len);
Ok(buf)
}
fn read_ext_body<'a, R>(rd: &mut R, len: usize, depth: u16) -> Result<(i8, &'a [u8]), Error>
where R: BorrowRead<'a>
{
let depth = super::decrement_depth(depth)?;
let ty = rd.read_data_i8()?;
let buf = read_bin_data(rd, len, depth)?;
Ok((ty, buf))
}
fn read_array_data<'a, R>(rd: &mut R, mut len: usize, depth: u16) -> Result<Vec<ValueRef<'a>>, Error>
where R: BorrowRead<'a>
{
let depth = super::decrement_depth(depth)?;
let mut vec = Vec::new();
while len > 0 {
vec.push(read_value_ref_inner(rd, depth)?);
len -= 1;
}
Ok(vec)
}
fn read_map_data<'a, R>(rd: &mut R, mut len: usize, depth: u16) -> Result<Vec<(ValueRef<'a>, ValueRef<'a>)>, Error>
where R: BorrowRead<'a>
{
let depth = super::decrement_depth(depth)?;
let mut vec = Vec::new();
while len > 0 {
vec.push((read_value_ref_inner(rd, depth)?, read_value_ref_inner(rd, depth)?));
len -= 1;
}
Ok(vec)
}
pub trait BorrowRead<'a>: Read {
fn fill_buf(&self) -> &'a [u8];
fn consume(&mut self, len: usize);
}
impl<'a> BorrowRead<'a> for &'a [u8] {
fn fill_buf(&self) -> &'a [u8] {
self
}
fn consume(&mut self, len: usize) {
*self = &(*self)[len..];
}
}
impl<'a> BorrowRead<'a> for Cursor<&'a [u8]> {
fn fill_buf(&self) -> &'a [u8] {
let len = std::cmp::min(self.position(), self.get_ref().len() as u64);
&self.get_ref()[len as usize..]
}
fn consume(&mut self, len: usize) {
let pos = self.position();
self.set_position(pos + len as u64);
}
}
fn read_value_ref_inner<'a, R>(rd: &mut R, depth: u16) -> Result<ValueRef<'a>, Error>
where R: BorrowRead<'a>
{
let depth = super::decrement_depth(depth)?;
let val = match read_marker(rd)? {
Marker::Null => ValueRef::Nil,
Marker::True => ValueRef::Boolean(true),
Marker::False => ValueRef::Boolean(false),
Marker::FixPos(val) => ValueRef::from(val),
Marker::FixNeg(val) => ValueRef::from(val),
Marker::U8 => ValueRef::from(rd.read_data_u8()?),
Marker::U16 => ValueRef::from(rd.read_data_u16()?),
Marker::U32 => ValueRef::from(rd.read_data_u32()?),
Marker::U64 => ValueRef::from(rd.read_data_u64()?),
Marker::I8 => ValueRef::from(rd.read_data_i8()?),
Marker::I16 => ValueRef::from(rd.read_data_i16()?),
Marker::I32 => ValueRef::from(rd.read_data_i32()?),
Marker::I64 => ValueRef::from(rd.read_data_i64()?),
Marker::F32 => ValueRef::F32(rd.read_data_f32()?),
Marker::F64 => ValueRef::F64(rd.read_data_f64()?),
Marker::FixStr(len) => {
let res = read_str_data(rd, len as usize, depth)?;
ValueRef::String(res)
}
Marker::Str8 => {
let len = rd.read_data_u8()?;
let res = read_str_data(rd, len as usize, depth)?;
ValueRef::String(res)
}
Marker::Str16 => {
let len = rd.read_data_u16()?;
let res = read_str_data(rd, len as usize, depth)?;
ValueRef::String(res)
}
Marker::Str32 => {
let len = rd.read_data_u32()?;
let res = read_str_data(rd, len as usize, depth)?;
ValueRef::String(res)
}
Marker::Bin8 => {
let len = rd.read_data_u8()?;
let res = read_bin_data(rd, len as usize, depth)?;
ValueRef::Binary(res)
}
Marker::Bin16 => {
let len = rd.read_data_u16()?;
let res = read_bin_data(rd, len as usize, depth)?;
ValueRef::Binary(res)
}
Marker::Bin32 => {
let len = rd.read_data_u32()?;
let res = read_bin_data(rd, len as usize, depth)?;
ValueRef::Binary(res)
}
Marker::FixArray(len) => {
let vec = read_array_data(rd, len as usize, depth)?;
ValueRef::Array(vec)
}
Marker::Array16 => {
let len = rd.read_data_u16()?;
let vec = read_array_data(rd, len as usize, depth)?;
ValueRef::Array(vec)
}
Marker::Array32 => {
let len = rd.read_data_u32()?;
let vec = read_array_data(rd, len as usize, depth)?;
ValueRef::Array(vec)
}
Marker::FixMap(len) => {
let map = read_map_data(rd, len as usize, depth)?;
ValueRef::Map(map)
}
Marker::Map16 => {
let len = rd.read_data_u16()?;
let map = read_map_data(rd, len as usize, depth)?;
ValueRef::Map(map)
}
Marker::Map32 => {
let len = rd.read_data_u32()?;
let map = read_map_data(rd, len as usize, depth)?;
ValueRef::Map(map)
}
Marker::FixExt1 => {
let len = 1;
let (ty, vec) = read_ext_body(rd, len as usize, depth)?;
ValueRef::Ext(ty, vec)
}
Marker::FixExt2 => {
let len = 2;
let (ty, vec) = read_ext_body(rd, len as usize, depth)?;
ValueRef::Ext(ty, vec)
}
Marker::FixExt4 => {
let len = 4;
let (ty, vec) = read_ext_body(rd, len as usize, depth)?;
ValueRef::Ext(ty, vec)
}
Marker::FixExt8 => {
let len = 8;
let (ty, vec) = read_ext_body(rd, len as usize, depth)?;
ValueRef::Ext(ty, vec)
}
Marker::FixExt16 => {
let len = 16;
let (ty, vec) = read_ext_body(rd, len as usize, depth)?;
ValueRef::Ext(ty, vec)
}
Marker::Ext8 => {
let len = rd.read_data_u8()?;
let (ty, vec) = read_ext_body(rd, len as usize, depth)?;
ValueRef::Ext(ty, vec)
}
Marker::Ext16 => {
let len = rd.read_data_u16()?;
let (ty, vec) = read_ext_body(rd, len as usize, depth)?;
ValueRef::Ext(ty, vec)
}
Marker::Ext32 => {
let len = rd.read_data_u32()?;
let (ty, vec) = read_ext_body(rd, len as usize, depth)?;
ValueRef::Ext(ty, vec)
}
Marker::Reserved => ValueRef::Nil,
};
Ok(val)
}
#[inline(never)]
pub fn read_value_ref<'a, R>(rd: &mut R) -> Result<ValueRef<'a>, Error>
where R: BorrowRead<'a>
{
read_value_ref_inner(rd, super::MAX_DEPTH as _)
}
#[inline(never)]
pub fn read_value_ref_with_max_depth<'a, R>(rd: &mut R, max_depth: usize) -> Result<ValueRef<'a>, Error>
where R: BorrowRead<'a>
{
read_value_ref_inner(rd, max_depth.min(u16::MAX as _) as u16)
}