use crate::{
deserializer::{
constants::{DECIMAL, END, I_16, I_32, I_64, REFERENCE_TAG},
consumed::Consumed,
read::{read_byte_at, read_exact_bytes},
},
error::Result,
};
pub fn read_signed_int(data: &[u8]) -> Result<Consumed<i64>> {
let mut offset = 0;
loop {
let current_byte = read_byte_at(data, offset)?;
let rest = &data[offset + 1..];
let (value, consumed) = match *current_byte {
I_16 => {
let size = 2;
let value = i16::from_le_bytes(<[u8; 2]>::try_from(read_exact_bytes(rest, size)?)?);
(i64::from(value), size + 1)
}
I_32 => {
let size = 4;
let value = i32::from_le_bytes(<[u8; 4]>::try_from(read_exact_bytes(rest, size)?)?);
(i64::from(value), size + 1)
}
I_64 => {
let size = 8;
let value = i64::from_le_bytes(<[u8; 8]>::try_from(read_exact_bytes(rest, size)?)?);
(value, size + 1)
}
_ => {
if current_byte > &(REFERENCE_TAG as u8) && *read_byte_at(data, offset + 1)? != END
{
offset += 1;
continue;
}
let value = i8::from_le_bytes([*current_byte]);
(i64::from(value), 1)
}
};
return Ok(Consumed::new(value, consumed));
}
}
pub fn read_unsigned_int(data: &[u8]) -> Result<Consumed<u64>> {
let mut offset = 0;
loop {
let current_byte = read_byte_at(data, offset)?;
let rest = &data[offset + 1..];
let (value, consumed) = match *current_byte {
I_16 => {
let size = 2;
let value = u16::from_le_bytes(<[u8; 2]>::try_from(read_exact_bytes(rest, size)?)?);
(u64::from(value), size + 1)
}
I_32 => {
let size = 4;
let value = u32::from_le_bytes(<[u8; 4]>::try_from(read_exact_bytes(rest, size)?)?);
(u64::from(value), size + 1)
}
I_64 => {
let size = 8;
let value = u64::from_le_bytes(<[u8; 8]>::try_from(read_exact_bytes(rest, size)?)?);
(value, size + 1)
}
_ => {
if current_byte > &(REFERENCE_TAG as u8) && *read_byte_at(data, offset + 1)? != END
{
offset += 1;
continue;
}
let value = u8::from_le_bytes([*current_byte]);
(u64::from(value), 1)
}
};
return Ok(Consumed::new(value, consumed));
}
}
pub fn read_float(data: &[u8]) -> Result<Consumed<f32>> {
let current_byte = read_byte_at(data, 0)?;
match *current_byte {
DECIMAL => {
let size = 4;
let value =
f32::from_le_bytes(<[u8; 4]>::try_from(read_exact_bytes(&data[1..], size)?)?);
Ok(Consumed::new(value, size + 1))
}
I_16 | I_32 => Ok(read_signed_int(data)?.map(|v| v as f32)),
_ => Ok(read_signed_int(data)?.map(|v| v as f32)),
}
}
pub fn read_double(data: &[u8]) -> Result<Consumed<f64>> {
let current_byte = read_byte_at(data, 0)?;
match *current_byte {
DECIMAL => {
let size = 8;
let value =
f64::from_le_bytes(<[u8; 8]>::try_from(read_exact_bytes(&data[1..], size)?)?);
Ok(Consumed::new(value, size + 1))
}
I_16 | I_32 => Ok(read_signed_int(data)?.map(|v| v as f64)),
_ => Ok(read_signed_int(data)?.map(|v| v as f64)),
}
}
#[cfg(test)]
mod int_tests {
use crate::deserializer::{
constants::{I_16, I_32},
number::{read_signed_int, read_unsigned_int},
};
#[test]
fn can_read_signed_int_small() {
let data = [0x01];
let result = read_signed_int(&data).unwrap();
assert_eq!(result.value, 1);
assert_eq!(result.bytes_consumed, 1);
}
#[test]
fn can_read_signed_int_16() {
let data = [I_16, 0x01, 0x01];
let result = read_signed_int(&data).unwrap();
assert_eq!(result.value, 257);
assert_eq!(result.bytes_consumed, 3);
}
#[test]
fn can_read_signed_int_1000() {
let data = [I_16, 0x01, 0x01];
let result = read_signed_int(&data).unwrap();
assert_eq!(result.value, 257);
assert_eq!(result.bytes_consumed, 3);
}
#[test]
fn can_read_signed_int_32() {
let data = [I_32, 0x01, 0x01, 0x01, 0x01];
let result = read_signed_int(&data).unwrap();
assert_eq!(result.value, 16843009);
assert_eq!(result.bytes_consumed, 5);
}
#[test]
fn can_read_unsigned_int_small() {
let data = [0x01];
let result = read_unsigned_int(&data).unwrap();
assert_eq!(result.value, 1);
assert_eq!(result.bytes_consumed, 1);
}
#[test]
fn can_read_unsigned_int_16() {
let data = [I_16, 0x01, 0x01];
let result = read_unsigned_int(&data).unwrap();
assert_eq!(result.value, 257);
assert_eq!(result.bytes_consumed, 3);
}
#[test]
fn can_read_unsigned_int_32() {
let data = [I_32, 0x01, 0x01, 0x01, 0x01];
let result = read_unsigned_int(&data).unwrap();
assert_eq!(result.value, 16843009);
assert_eq!(result.bytes_consumed, 5);
}
#[test]
fn cant_read_unsigned_int_16_too_short() {
let data = [I_16, 0x01];
let result = read_unsigned_int(&data);
assert!(result.is_err());
}
#[test]
fn cant_read_unsigned_int_32_too_short() {
let data = [I_32, 0x01, 0x01, 0x01];
let result = read_unsigned_int(&data);
assert!(result.is_err());
}
#[test]
fn can_read_signed_int_64() {
let data = [0x87, 0x00, 0x28, 0x6b, 0xee, 0x00, 0x00, 0x00, 0x00, 0x86];
let result = read_signed_int(&data).unwrap();
assert_eq!(result.value, 4_000_000_000);
assert_eq!(result.bytes_consumed, 9);
}
#[test]
fn can_read_signed_int_64_negative() {
let data = [0x87, 0x00, 0xe6, 0x8e, 0xe7, 0xfd, 0xff, 0xff, 0xff, 0x86];
let result = read_signed_int(&data).unwrap();
assert_eq!(result.value, -9_000_000_000);
assert_eq!(result.bytes_consumed, 9);
}
#[test]
fn can_read_unsigned_int_64() {
let data = [0x87, 0x00, 0x34, 0xe2, 0x30, 0x04, 0x00, 0x00, 0x00, 0x86];
let result = read_unsigned_int(&data).unwrap();
assert_eq!(result.value, 18_000_000_000);
assert_eq!(result.bytes_consumed, 9);
}
#[test]
fn cant_read_signed_int_64_too_short() {
let data = [0x87, 0x00, 0x28, 0x6b, 0xee];
let result = read_signed_int(&data);
assert!(result.is_err());
}
}
#[cfg(test)]
mod float_tests {
use crate::deserializer::{
constants::{DECIMAL, I_16, I_32},
number::{read_double, read_float},
};
#[test]
fn can_read_float_small() {
let data = [0x01];
let result = read_float(&data).unwrap();
assert_eq!(result.value, 1.);
assert_eq!(result.bytes_consumed, 1);
}
#[test]
fn can_read_float_16() {
let data = [I_16, 0x01, 0x01];
let result = read_float(&data).unwrap();
assert_eq!(result.value, 257.);
assert_eq!(result.bytes_consumed, 3);
}
#[test]
fn can_read_float_32() {
let data = [I_32, 0x01, 0x01, 0x01, 0x01];
let result = read_float(&data).unwrap();
assert_eq!(result.value, 16843009.);
assert_eq!(result.bytes_consumed, 5);
}
#[test]
fn can_read_double_small() {
let data = [0x01];
let result = read_double(&data).unwrap();
assert_eq!(result.value, 1.);
assert_eq!(result.bytes_consumed, 1);
}
#[test]
fn can_read_double_16() {
let data = [I_16, 0x01, 0x01];
let result = read_double(&data).unwrap();
assert_eq!(result.value, 257.);
assert_eq!(result.bytes_consumed, 3);
}
#[test]
fn can_read_double_32() {
let data = [I_32, 0x01, 0x01, 0x01, 0x01];
let result = read_double(&data).unwrap();
assert_eq!(result.value, 16843009.);
assert_eq!(result.bytes_consumed, 5);
}
#[test]
fn can_read_decimal_float() {
let data = [DECIMAL, 0x00, 0x00, 0x60, 0x40, 0x86];
let result = read_float(&data).unwrap();
assert_eq!(result.value, 3.5);
assert_eq!(result.bytes_consumed, 5);
}
#[test]
fn can_read_decimal_float_one() {
let data = [DECIMAL, 0x00, 0x00, 0x80, 0x3F];
let result = read_float(&data).unwrap();
assert_eq!(result.value, 1.0);
assert_eq!(result.bytes_consumed, 5);
}
#[test]
fn can_read_decimal_double() {
let data = [
DECIMAL, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x59, 0x40, 0x86,
];
let result = read_double(&data).unwrap();
assert_eq!(result.value, 100.5);
assert_eq!(result.bytes_consumed, 9);
}
#[test]
fn can_read_decimal_double_fractional_date() {
let data = [
DECIMAL, 0xaa, 0xf1, 0x42, 0x80, 0x93, 0xdc, 0xc4, 0x41, 0x86,
];
let result = read_double(&data).unwrap();
assert!(
(result.value - 700_000_000.523).abs() < 1e-3,
"got {}",
result.value
);
assert_eq!(result.bytes_consumed, 9);
}
#[test]
fn cant_read_decimal_double_too_short() {
let data = [DECIMAL, 0x9b, 0x91, 0x04, 0x8b];
let result = read_double(&data);
assert!(result.is_err());
}
}