use core::convert::TryInto;
use crate::{bsl::Len, visit::Parse, Error, ParseResult, SResult, Visit};
#[derive(Debug, PartialEq, Eq)]
#[allow(deprecated)]
pub struct U8([u8; 1]);
impl AsRef<[u8]> for U8 {
fn as_ref(&self) -> &[u8] {
&self.0[..]
}
}
impl From<U8> for u8 {
fn from(u: U8) -> Self {
u.0[0]
}
}
impl From<&U8> for u8 {
fn from(u: &U8) -> Self {
u.0[0]
}
}
impl From<u8> for U8 {
fn from(u: u8) -> Self {
U8([u])
}
}
impl<'a> Parse<'a> for U8 {
fn parse(slice: &'a [u8]) -> SResult<'a, Self> {
#[allow(deprecated)]
let p = crate::slice::read_slice(slice, 1)?;
Ok(ParseResult::new(p.remaining(), U8([p.parsed()[0]])))
}
}
macro_rules! impl_number {
($primitive:ty, $newtype:ident, $size:expr) => {
#[doc=concat!("Converts into and from ", stringify!($primitive), " and implements [`Visit`] and `AsRef<[u8]>`." )]
#[derive(Debug, PartialEq, Eq)]
pub struct $newtype([u8; $size]);
impl<'a> Visit<'a> for $newtype {
fn visit<'b, V: crate::Visitor>(
slice: &'a [u8],
_visit: &'b mut V,
) -> SResult<'a, Self> {
#[allow(deprecated)]
let p = crate::slice::read_slice(slice, $size)?;
let remaining = p.remaining();
let arr = p
.parsed_owned()
.try_into()
.expect(concat!("slice length is ", $size));
Ok(ParseResult::new(remaining, $newtype(arr)))
}
}
impl From<$newtype> for $primitive {
fn from(u: $newtype) -> Self {
<$primitive>::from_le_bytes(u.0)
}
}
impl From<&$newtype> for $primitive {
fn from(u: &$newtype) -> Self {
<$primitive>::from_le_bytes(u.0)
}
}
impl From<$primitive> for $newtype {
fn from(u: $primitive) -> Self {
$newtype(u.to_le_bytes())
}
}
impl AsRef<[u8]> for $newtype {
fn as_ref(&self) -> &[u8] {
&self.0[..]
}
}
};
}
impl_number!(u16, U16, 2);
impl_number!(u32, U32, 4);
impl_number!(i32, I32, 4);
impl_number!(u64, U64, 8);
impl U64 {
pub fn to_len(self) -> Result<Len, Error> {
let n: u64 = self.into();
if n > u32::MAX as u64 {
Ok(Len { n, consumed: 9 })
} else {
Err(Error::NonMinimalVarInt)
}
}
}
impl U32 {
pub fn to_len(self) -> Result<Len, Error> {
let n: u64 = u32::from(self) as u64;
if n > u16::MAX as u64 {
Ok(Len { n, consumed: 5 })
} else {
Err(Error::NonMinimalVarInt)
}
}
}
impl U16 {
pub fn to_len(self) -> Result<Len, Error> {
let n: u64 = u16::from(self) as u64;
if n >= 0xFD {
Ok(Len { n, consumed: 3 })
} else {
Err(Error::NonMinimalVarInt)
}
}
}
#[inline(always)]
pub fn read_u8(slice: &[u8]) -> Result<u8, Error> {
slice.first().cloned().ok_or(Error::MoreBytesNeeded)
}
#[inline(always)]
pub fn read_u16(slice: &[u8]) -> Result<u16, Error> {
let arr: [u8; 2] = slice
.get(..2)
.ok_or(Error::MoreBytesNeeded)?
.try_into()
.expect("slice length is 2");
Ok(u16::from_le_bytes(arr))
}
#[inline(always)]
pub fn read_u32(slice: &[u8]) -> Result<u32, Error> {
if slice.len() < 4 {
return Err(Error::MoreBytesNeeded);
}
Ok(u32::from_le_bytes([slice[0], slice[1], slice[2], slice[3]]))
}
#[inline(always)]
pub fn read_i32(slice: &[u8]) -> Result<i32, Error> {
if slice.len() < 4 {
return Err(Error::MoreBytesNeeded);
}
Ok(i32::from_le_bytes([slice[0], slice[1], slice[2], slice[3]]))
}
#[inline(always)]
pub fn read_u64(slice: &[u8]) -> Result<u64, Error> {
if slice.len() < 8 {
return Err(Error::MoreBytesNeeded);
}
Ok(u64::from_le_bytes([
slice[0], slice[1], slice[2], slice[3], slice[4], slice[5], slice[6], slice[7],
]))
}
#[cfg(test)]
mod test {
use crate::ParseResult;
use super::*;
#[test]
fn test_read_functions() {
assert_eq!(read_u8(&[1u8]), Ok(1u8));
assert_eq!(read_u8(&[255u8]), Ok(255u8));
assert_eq!(read_u8(&[1u8, 2]), Ok(1u8));
assert_eq!(read_u8(&[]), Err(Error::MoreBytesNeeded));
assert_eq!(read_u32(&[1u8, 0, 0, 0]), Ok(1u32));
assert_eq!(read_u32(&[0u8, 1, 0, 0]), Ok(256u32));
assert_eq!(read_u32(&[136u8, 19, 0, 0]), Ok(5000u32));
assert_eq!(read_u32(&[32u8, 161, 7, 0]), Ok(500000u32));
assert_eq!(read_u32(&[10u8, 10, 10, 10]), Ok(168430090u32));
assert_eq!(read_u32(&[1u8]), Err(Error::MoreBytesNeeded));
assert_eq!(read_u32(&[1u8, 2]), Err(Error::MoreBytesNeeded));
assert_eq!(read_u32(&[1u8, 2, 3]), Err(Error::MoreBytesNeeded));
assert_eq!(read_i32(&[255u8, 255, 255, 255]), Ok(-1i32));
assert_eq!(read_i32(&[0u8, 255, 255, 255]), Ok(-256i32));
assert_eq!(read_i32(&[120u8, 236, 255, 255]), Ok(-5000i32));
assert_eq!(read_i32(&[32u8, 161, 7, 0]), Ok(500000i32));
assert_eq!(read_i32(&[1u8]), Err(Error::MoreBytesNeeded));
assert_eq!(read_i32(&[1u8, 2]), Err(Error::MoreBytesNeeded));
assert_eq!(read_i32(&[1u8, 2, 3]), Err(Error::MoreBytesNeeded));
assert_eq!(read_u64(&[1u8, 0, 0, 0, 0, 0, 0, 0]), Ok(1u64));
assert_eq!(
read_u64(&[10u8, 10, 10, 10, 10, 10, 10, 10]),
Ok(723401728380766730u64)
);
assert_eq!(read_u64(&[1u8]), Err(Error::MoreBytesNeeded));
assert_eq!(read_u64(&[1u8, 2, 3, 4]), Err(Error::MoreBytesNeeded));
assert_eq!(
read_u64(&[1u8, 2, 3, 4, 5, 6, 7]),
Err(Error::MoreBytesNeeded)
);
}
#[test]
fn numbers() {
assert_eq!(
U8::parse(&[0u8][..]),
Ok(ParseResult::new(&[][..], 0u8.into()))
);
assert_eq!(
U8::parse(&[1u8][..]),
Ok(ParseResult::new(&[][..], 1u8.into()))
);
assert_eq!(
U8::parse(&[255u8][..]),
Ok(ParseResult::new(&[][..], 255u8.into()))
);
assert_eq!(
U8::parse(&[1u8, 2][..]),
Ok(ParseResult::new(&[2u8][..], 1u8.into()))
);
assert_eq!(
U16::parse(&[1u8, 0][..]),
Ok(ParseResult::new(&[][..], 1u16.into()))
);
assert_eq!(
U16::parse(&[0u8, 1][..]),
Ok(ParseResult::new(&[][..], 256u16.into()))
);
assert_eq!(
U16::parse(&[136u8, 19][..]),
Ok(ParseResult::new(&[][..], 5000u16.into()))
);
assert_eq!(
U16::parse(&[136u8, 19, 2][..]),
Ok(ParseResult::new(&[2u8][..], 5000u16.into()))
);
assert_eq!(
U32::parse(&[1u8, 0, 0, 0][..]),
Ok(ParseResult::new(&[][..], 1u32.into()))
);
assert_eq!(
U32::parse(&[0u8, 1, 0, 0][..]),
Ok(ParseResult::new(&[][..], 256u32.into()))
);
assert_eq!(
U32::parse(&[136u8, 19, 0, 0][..]),
Ok(ParseResult::new(&[][..], 5000u32.into()))
);
assert_eq!(
U32::parse(&[32u8, 161, 7, 0][..]),
Ok(ParseResult::new(&[][..], 500000u32.into()))
);
assert_eq!(
U32::parse(&[10u8, 10, 10, 10][..]),
Ok(ParseResult::new(&[][..], 168430090u32.into()))
);
assert_eq!(
I32::parse(&[255u8, 255, 255, 255][..]),
Ok(ParseResult::new(&[][..], (-1i32).into()))
);
assert_eq!(
I32::parse(&[0u8, 255, 255, 255][..]),
Ok(ParseResult::new(&[][..], (-256i32).into()))
);
assert_eq!(
I32::parse(&[120u8, 236, 255, 255][..]),
Ok(ParseResult::new(&[][..], (-5000i32).into()))
);
assert_eq!(
I32::parse(&[32u8, 161, 7, 0][..]),
Ok(ParseResult::new(&[][..], 500000i32.into()))
);
assert_eq!(
U64::parse(&[1u8, 0, 0, 0, 0, 0, 0, 0][..]),
Ok(ParseResult::new(&[][..], 1u64.into()))
);
assert_eq!(
U64::parse(&[10u8, 10, 10, 10, 10, 10, 10, 10][..]),
Ok(ParseResult::new(&[][..], 723401728380766730u64.into()))
);
}
}