use errors::{Result, ResultExt};
use u128;
use std::io::Read;
use byteorder::{BigEndian, ReadBytesExt};
pub fn read_bool<R: Read>(reader: &mut R) -> Result<bool> {
let byte = read_u8(reader)?;
match byte {
0 => Ok(false),
1 => Ok(true),
_ => bail!("Bool had invalid value {}", byte),
}
}
pub fn read_i8<R: Read>(reader: &mut R) -> Result<i8> {
Ok(reader.read_i8()?)
}
pub fn read_u8<R: Read>(reader: &mut R) -> Result<u8> {
Ok(reader.read_u8()?)
}
pub fn read_i16<R: Read>(reader: &mut R) -> Result<i16> {
Ok(reader.read_i16::<BigEndian>()?)
}
pub fn read_u16<R: Read>(reader: &mut R) -> Result<u16> {
Ok(reader.read_u16::<BigEndian>()?)
}
pub fn read_i32<R: Read>(reader: &mut R) -> Result<i32> {
Ok(reader.read_i32::<BigEndian>()?)
}
pub fn read_i64<R: Read>(reader: &mut R) -> Result<i64> {
Ok(reader.read_i64::<BigEndian>()?)
}
pub fn read_u64<R: Read>(reader: &mut R) -> Result<u64> {
Ok(reader.read_u64::<BigEndian>()?)
}
pub fn read_f32<R: Read>(reader: &mut R) -> Result<f32> {
Ok(reader.read_f32::<BigEndian>()?)
}
pub fn read_f64<R: Read>(reader: &mut R) -> Result<f64> {
Ok(reader.read_f64::<BigEndian>()?)
}
#[allow(non_snake_case)]
pub fn read_String<R: Read>(reader: &mut R) -> Result<String> {
let length = read_varint(reader)? as usize;
if length > (1 << 16) {
bail!("read_string refusing to read string due to its length");
}
let mut ret = String::with_capacity(length);
let read = reader.take(length as u64).read_to_string(&mut ret)?;
if read != length {
bail!("read_String expected a string with length {} but was only able to read {} bytes", length, read);
}
Ok(ret)
}
pub fn read_varint<R: Read>(reader: &mut R) -> Result<i32> {
let mut radix: u64 = 128;
let msb: u8 = 0b10000000;
let mut buf = reader.read_u8()?;
let mut res = (buf & (!msb)) as u64;
let mut i: usize = 0;
while (buf & msb) != 0 {
if i >= 5 {
bail!("VarInt is too long");
}
i += 1;
buf = reader.read_u8()?;
res += ((buf & (!msb)) as u64) * radix;
radix <<= 7;
}
if res >= 4294967296 {
bail!("Received too large varint");
}
if res > 2147483647 {
return Ok((4294967296 - res) as i32 * -1);
} else {
return Ok(res as i32);
}
}
pub fn read_prefixed_bytearray<R: Read>(reader: &mut R) -> Result<Vec<u8>> {
let length = read_varint(reader)?;
let mut tmp = vec![0; length as usize];
reader.read_exact(&mut tmp)?;
Ok(tmp)
}
pub fn read_prefixed_varintarray<R: Read>(reader: &mut R) -> Result<Vec<i32>> {
let length = read_varint(reader)?;
let mut tmp = Vec::with_capacity(length as usize);
for _ in 0..length {
tmp.push(read_varint(reader)?);
}
Ok(tmp)
}
pub fn read_uuid<R: Read>(reader: &mut R) -> Result<u128> {
let a = read_u64(reader)?;
let b = read_u64(reader)?;
Ok(u128(a, b))
}
pub fn read_uuid_str<R: Read>(reader: &mut R) -> Result<u128> {
let tmp = read_String(reader)?.replace("-", "");
let a = u64::from_str_radix(&tmp[..16], 16)
.chain_err(|| "Invalid hex in first half of uuid_str")?;
let b = u64::from_str_radix(&tmp[16..], 16)
.chain_err(|| "Invalid hex in second half of uuid_str")?;
Ok(u128(a, b))
}
pub fn read_bytearray_to_end<R: Read>(reader: &mut R) -> Result<Vec<u8>> {
let mut tmp = Vec::new();
reader.read_to_end(&mut tmp)?;
Ok(tmp)
}
pub fn read_bytearray<R: Read>(reader: &mut R) -> Result<Vec<u8>> {
read_bytearray_to_end(reader)
}
pub fn read_position<R: Read>(reader: &mut R) -> Result<(i32, i32, i32)> {
let val = read_u64(reader)?;
let mut x = (val >> 38) as i32;
let mut y = ((val >> 26) & 0xfff) as i32;
let mut z = (val & 0x3ffffff) as i32;
if x >= 1 << 25 {
x -= 1 << 26;
}
if y >= 1 << 11 {
y -= 1 << 12;
}
if z >= 2 << 25 {
z -= 1 << 26;
}
Ok((x, y, z))
}