use std::convert::TryInto;
use std::io;
use std::mem::{forget, size_of};
mod hint;
const ERROR_NOT_ALL_BYTES_READ: &str = "Not all bytes read";
const ERROR_UNEXPECTED_LENGTH_OF_INPUT: &str = "Unexpected length of input";
pub trait OBIDecode: Sized {
fn decode(buf: &mut &[u8]) -> io::Result<Self>;
fn try_from_slice(v: &[u8]) -> io::Result<Self> {
let mut v_mut = v;
let result = Self::decode(&mut v_mut)?;
if !v_mut.is_empty() {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
ERROR_NOT_ALL_BYTES_READ,
));
}
Ok(result)
}
#[inline]
fn is_u8() -> bool {
false
}
}
impl OBIDecode for u8 {
#[inline]
fn decode(buf: &mut &[u8]) -> io::Result<Self> {
if buf.is_empty() {
return Err(io::Error::new(
io::ErrorKind::InvalidInput,
ERROR_UNEXPECTED_LENGTH_OF_INPUT,
));
}
let res = buf[0];
*buf = &buf[1..];
Ok(res)
}
#[inline]
fn is_u8() -> bool {
true
}
}
macro_rules! impl_for_integer {
($type: ident) => {
impl OBIDecode for $type {
#[inline]
fn decode(buf: &mut &[u8]) -> io::Result<Self> {
if buf.len() < size_of::<$type>() {
return Err(io::Error::new(
io::ErrorKind::InvalidInput,
ERROR_UNEXPECTED_LENGTH_OF_INPUT,
));
}
let res = $type::from_be_bytes(buf[..size_of::<$type>()].try_into().unwrap());
*buf = &buf[size_of::<$type>()..];
Ok(res)
}
}
};
}
impl_for_integer!(i8);
impl_for_integer!(i16);
impl_for_integer!(i32);
impl_for_integer!(i64);
impl_for_integer!(i128);
impl_for_integer!(u16);
impl_for_integer!(u32);
impl_for_integer!(u64);
impl_for_integer!(u128);
impl OBIDecode for bool {
#[inline]
fn decode(buf: &mut &[u8]) -> io::Result<Self> {
if buf.is_empty() {
return Err(io::Error::new(
io::ErrorKind::InvalidInput,
ERROR_UNEXPECTED_LENGTH_OF_INPUT,
));
}
let b = buf[0];
*buf = &buf[1..];
if b == 0 {
Ok(false)
} else if b == 1 {
Ok(true)
} else {
Err(io::Error::new(
io::ErrorKind::InvalidInput,
format!("Invalid bool representation: {}", b),
))
}
}
}
#[cfg(feature = "std")]
impl<T> OBIDecode for Vec<T>
where
T: OBIDecode,
{
#[inline]
fn decode(buf: &mut &[u8]) -> io::Result<Self> {
let len = u32::decode(buf)?;
if len == 0 {
Ok(Vec::new())
} else if T::is_u8() && size_of::<T>() == size_of::<u8>() {
let len = len as usize;
if buf.len() < len {
return Err(io::Error::new(
io::ErrorKind::InvalidInput,
ERROR_UNEXPECTED_LENGTH_OF_INPUT,
));
}
let result = buf[..len].to_vec();
*buf = &buf[len..];
let result = unsafe {
let mut v_clone = std::mem::ManuallyDrop::new(result);
Vec::from_raw_parts(
v_clone.as_mut_ptr() as *mut T,
v_clone.len(),
v_clone.capacity(),
)
};
Ok(result)
} else if size_of::<T>() == 0 {
let mut result = Vec::new();
result.push(T::decode(buf)?);
let p = result.as_mut_ptr();
unsafe {
forget(result);
let len = len as usize;
let result = Vec::from_raw_parts(p, len, len);
Ok(result)
}
} else {
let mut result = Vec::with_capacity(hint::cautious::<T>(len));
for _ in 0..len {
result.push(T::decode(buf)?);
}
Ok(result)
}
}
}
impl OBIDecode for String {
#[inline]
fn decode(buf: &mut &[u8]) -> io::Result<Self> {
String::from_utf8(Vec::<u8>::decode(buf)?)
.map_err(|err| io::Error::new(io::ErrorKind::InvalidData, err.to_string()))
}
}