use qubit_codec::Codec;
use qubit_codec_binary::{
BigEndian,
BinaryCodec,
LittleEndian,
};
use super::assertions_tests::assert_decoded_eq;
#[test]
fn test_binary_codec_exposes_unit_bounds() {
assert_eq!(1, BinaryCodec::<u8, BigEndian>::MIN_UNITS_PER_VALUE);
assert_eq!(1, BinaryCodec::<u8, BigEndian>::MAX_UNITS_PER_VALUE);
assert_eq!(1, BinaryCodec::<i8, LittleEndian>::MIN_UNITS_PER_VALUE);
assert_eq!(1, BinaryCodec::<i8, LittleEndian>::MAX_UNITS_PER_VALUE);
assert_eq!(2, BinaryCodec::<u16, BigEndian>::MIN_UNITS_PER_VALUE);
assert_eq!(2, BinaryCodec::<u16, BigEndian>::MAX_UNITS_PER_VALUE);
assert_eq!(4, BinaryCodec::<u32, LittleEndian>::MIN_UNITS_PER_VALUE);
assert_eq!(4, BinaryCodec::<u32, LittleEndian>::MAX_UNITS_PER_VALUE);
assert_eq!(8, BinaryCodec::<u64, BigEndian>::MIN_UNITS_PER_VALUE);
assert_eq!(8, BinaryCodec::<u64, BigEndian>::MAX_UNITS_PER_VALUE);
assert_eq!(16, BinaryCodec::<u128, LittleEndian>::MIN_UNITS_PER_VALUE);
assert_eq!(16, BinaryCodec::<u128, LittleEndian>::MAX_UNITS_PER_VALUE);
assert_eq!(4, BinaryCodec::<f32, BigEndian>::MIN_UNITS_PER_VALUE);
assert_eq!(4, BinaryCodec::<f32, BigEndian>::MAX_UNITS_PER_VALUE);
assert_eq!(8, BinaryCodec::<f64, LittleEndian>::MIN_UNITS_PER_VALUE);
assert_eq!(8, BinaryCodec::<f64, LittleEndian>::MAX_UNITS_PER_VALUE);
}
#[test]
fn test_binary_codec_reads_from_explicit_index_unchecked() {
let input = [0xaa, 0x12, 0x34, 0x56, 0x78, 0xbb];
let decoded =
unsafe { BinaryCodec::<u32, BigEndian>::decode_unchecked(&input, 1) };
assert_decoded_eq((0x1234_5678, 4), decoded);
let decoded = unsafe {
BinaryCodec::<u32, LittleEndian>::decode_unchecked(&input, 1)
};
assert_decoded_eq((0x7856_3412, 4), decoded);
}
#[test]
fn test_binary_codec_writes_to_explicit_index_unchecked() {
let mut output = [0xaa, 0, 0, 0, 0, 0xbb];
unsafe {
assert_eq!(
4,
BinaryCodec::<u32, BigEndian>::encode_unchecked(
0x1234_5678,
&mut output,
1
)
);
}
assert_eq!([0xaa, 0x12, 0x34, 0x56, 0x78, 0xbb], output);
unsafe {
assert_eq!(
4,
BinaryCodec::<u32, LittleEndian>::encode_unchecked(
0x1234_5678,
&mut output,
1
)
);
}
assert_eq!([0xaa, 0x78, 0x56, 0x34, 0x12, 0xbb], output);
}
#[test]
fn test_binary_codec_roundtrips_integer_extremes_for_all_fixed_width_types() {
macro_rules! assert_extreme_roundtrip {
($ty:ty, $value:expr) => {{
let value: $ty = $value;
let mut output =
[0u8; BinaryCodec::<$ty, BigEndian>::MAX_UNITS_PER_VALUE];
let written = unsafe {
BinaryCodec::<$ty, BigEndian>::encode_unchecked(
value,
&mut output,
0,
)
};
assert_eq!(output.len(), written);
assert_eq!(value.to_be_bytes(), output);
let decoded = unsafe {
BinaryCodec::<$ty, BigEndian>::decode_unchecked(&output, 0)
};
assert_decoded_eq((value, output.len()), decoded);
let mut output =
[0u8; BinaryCodec::<$ty, LittleEndian>::MAX_UNITS_PER_VALUE];
let written = unsafe {
BinaryCodec::<$ty, LittleEndian>::encode_unchecked(
value,
&mut output,
0,
)
};
assert_eq!(output.len(), written);
assert_eq!(value.to_le_bytes(), output);
let decoded = unsafe {
BinaryCodec::<$ty, LittleEndian>::decode_unchecked(&output, 0)
};
assert_decoded_eq((value, output.len()), decoded);
}};
}
assert_extreme_roundtrip!(u8, u8::MIN);
assert_extreme_roundtrip!(u8, u8::MAX);
assert_extreme_roundtrip!(i8, i8::MIN);
assert_extreme_roundtrip!(i8, i8::MAX);
assert_extreme_roundtrip!(u16, u16::MIN);
assert_extreme_roundtrip!(u16, u16::MAX);
assert_extreme_roundtrip!(i16, i16::MIN);
assert_extreme_roundtrip!(i16, i16::MAX);
assert_extreme_roundtrip!(u32, u32::MIN);
assert_extreme_roundtrip!(u32, u32::MAX);
assert_extreme_roundtrip!(i32, i32::MIN);
assert_extreme_roundtrip!(i32, i32::MAX);
assert_extreme_roundtrip!(u64, u64::MIN);
assert_extreme_roundtrip!(u64, u64::MAX);
assert_extreme_roundtrip!(i64, i64::MIN);
assert_extreme_roundtrip!(i64, i64::MAX);
assert_extreme_roundtrip!(u128, u128::MIN);
assert_extreme_roundtrip!(u128, u128::MAX);
assert_extreme_roundtrip!(i128, i128::MIN);
assert_extreme_roundtrip!(i128, i128::MAX);
}
#[test]
fn test_binary_codec_preserves_f32_bit_patterns() {
macro_rules! assert_f32_bit_roundtrip {
($bits:expr) => {{
let bits: u32 = $bits;
let value = f32::from_bits(bits);
let mut output =
[0u8; BinaryCodec::<f32, BigEndian>::MAX_UNITS_PER_VALUE];
let written = unsafe {
BinaryCodec::<f32, BigEndian>::encode_unchecked(
value,
&mut output,
0,
)
};
assert_eq!(output.len(), written);
assert_eq!(bits.to_be_bytes(), output);
let (decoded, consumed) = unsafe {
BinaryCodec::<f32, BigEndian>::decode_unchecked(&output, 0)
};
assert_eq!(bits, decoded.to_bits());
assert_eq!(output.len(), consumed.get());
let mut output =
[0u8; BinaryCodec::<f32, LittleEndian>::MAX_UNITS_PER_VALUE];
let written = unsafe {
BinaryCodec::<f32, LittleEndian>::encode_unchecked(
value,
&mut output,
0,
)
};
assert_eq!(output.len(), written);
assert_eq!(bits.to_le_bytes(), output);
let (decoded, consumed) = unsafe {
BinaryCodec::<f32, LittleEndian>::decode_unchecked(&output, 0)
};
assert_eq!(bits, decoded.to_bits());
assert_eq!(output.len(), consumed.get());
}};
}
assert_f32_bit_roundtrip!(0x8000_0000);
assert_f32_bit_roundtrip!(0x7f80_0000);
assert_f32_bit_roundtrip!(0xff80_0000);
assert_f32_bit_roundtrip!(0x7fc0_0123);
}
#[test]
fn test_binary_codec_preserves_f64_bit_patterns() {
macro_rules! assert_f64_bit_roundtrip {
($bits:expr) => {{
let bits: u64 = $bits;
let value = f64::from_bits(bits);
let mut output =
[0u8; BinaryCodec::<f64, BigEndian>::MAX_UNITS_PER_VALUE];
let written = unsafe {
BinaryCodec::<f64, BigEndian>::encode_unchecked(
value,
&mut output,
0,
)
};
assert_eq!(output.len(), written);
assert_eq!(bits.to_be_bytes(), output);
let (decoded, consumed) = unsafe {
BinaryCodec::<f64, BigEndian>::decode_unchecked(&output, 0)
};
assert_eq!(bits, decoded.to_bits());
assert_eq!(output.len(), consumed.get());
let mut output =
[0u8; BinaryCodec::<f64, LittleEndian>::MAX_UNITS_PER_VALUE];
let written = unsafe {
BinaryCodec::<f64, LittleEndian>::encode_unchecked(
value,
&mut output,
0,
)
};
assert_eq!(output.len(), written);
assert_eq!(bits.to_le_bytes(), output);
let (decoded, consumed) = unsafe {
BinaryCodec::<f64, LittleEndian>::decode_unchecked(&output, 0)
};
assert_eq!(bits, decoded.to_bits());
assert_eq!(output.len(), consumed.get());
}};
}
assert_f64_bit_roundtrip!(0x8000_0000_0000_0000);
assert_f64_bit_roundtrip!(0x7ff0_0000_0000_0000);
assert_f64_bit_roundtrip!(0xfff0_0000_0000_0000);
assert_f64_bit_roundtrip!(0x7ff8_0000_0000_1234);
}
#[test]
fn test_binary_codec_encodes_and_decodes_through_codec_trait() {
let codec = BinaryCodec::<u32, BigEndian>::default();
let mut output = [0xaa, 0, 0, 0, 0, 0xbb];
assert_eq!(4, codec.min_units_per_value().get());
assert_eq!(4, codec.max_units_per_value().get());
let written = unsafe {
Codec::encode_unchecked(&codec, &0x1234_5678, &mut output, 1)
}
.expect("fixed-width encoding should be infallible");
assert_eq!(4, written);
assert_eq!([0xaa, 0x12, 0x34, 0x56, 0x78, 0xbb], output);
let (decoded, consumed) =
unsafe { Codec::decode_unchecked(&codec, &output, 1) }
.expect("fixed-width decoding should be infallible");
assert_eq!(0x1234_5678, decoded);
assert_eq!(4, consumed.get());
}
#[test]
fn test_binary_codec_trait_covers_byte_and_little_endian_groups() {
let unsigned_byte = BinaryCodec::<u8, BigEndian>::default();
let signed_byte = BinaryCodec::<i8, LittleEndian>::default();
let little_integer = BinaryCodec::<u16, LittleEndian>::default();
let big_float = BinaryCodec::<f32, BigEndian>::default();
let little_float = BinaryCodec::<f64, LittleEndian>::default();
let mut output = [0u8; 24];
assert_eq!(1, unsigned_byte.min_units_per_value().get());
assert_eq!(1, unsigned_byte.max_units_per_value().get());
assert_eq!(1, signed_byte.min_units_per_value().get());
assert_eq!(1, signed_byte.max_units_per_value().get());
assert_eq!(2, little_integer.min_units_per_value().get());
assert_eq!(2, little_integer.max_units_per_value().get());
assert_eq!(4, big_float.min_units_per_value().get());
assert_eq!(4, big_float.max_units_per_value().get());
assert_eq!(8, little_float.min_units_per_value().get());
assert_eq!(8, little_float.max_units_per_value().get());
assert_eq!(
1,
unsafe {
Codec::encode_unchecked(&unsigned_byte, &0x7f, &mut output, 0)
}
.expect("u8 encoding should be infallible")
);
assert_eq!(
1,
unsafe { Codec::encode_unchecked(&signed_byte, &-1, &mut output, 1) }
.expect("i8 encoding should be infallible")
);
assert_eq!(
2,
unsafe {
Codec::encode_unchecked(&little_integer, &0x1234, &mut output, 2)
}
.expect("little-endian integer encoding should be infallible")
);
assert_eq!(
4,
unsafe { Codec::encode_unchecked(&big_float, &12.5, &mut output, 4) }
.expect("big-endian float encoding should be infallible")
);
assert_eq!(
8,
unsafe {
Codec::encode_unchecked(&little_float, &-25.25, &mut output, 8)
}
.expect("little-endian float encoding should be infallible")
);
let (decoded, consumed) =
unsafe { Codec::decode_unchecked(&unsigned_byte, &output, 0) }
.expect("u8 decoding should be infallible");
assert_eq!(0x7f, decoded);
assert_eq!(1, consumed.get());
let (decoded, consumed) =
unsafe { Codec::decode_unchecked(&signed_byte, &output, 1) }
.expect("i8 decoding should be infallible");
assert_eq!(-1, decoded);
assert_eq!(1, consumed.get());
let (decoded, consumed) =
unsafe { Codec::decode_unchecked(&little_integer, &output, 2) }
.expect("little-endian integer decoding should be infallible");
assert_eq!(0x1234, decoded);
assert_eq!(2, consumed.get());
let (decoded, consumed) =
unsafe { Codec::decode_unchecked(&big_float, &output, 4) }
.expect("big-endian float decoding should be infallible");
assert_eq!(12.5, decoded);
assert_eq!(4, consumed.get());
let (decoded, consumed) =
unsafe { Codec::decode_unchecked(&little_float, &output, 8) }
.expect("little-endian float decoding should be infallible");
assert_eq!(-25.25, decoded);
assert_eq!(8, consumed.get());
}
#[test]
fn test_binary_codec_handles_byte_signed_and_float_values() {
let mut output = [0u8; 16];
unsafe {
assert_eq!(
1,
BinaryCodec::<u8, BigEndian>::encode_unchecked(
0x7f,
&mut output,
0
)
);
assert_eq!(
1,
BinaryCodec::<i8, LittleEndian>::encode_unchecked(
-1,
&mut output,
1
)
);
assert_eq!(
4,
BinaryCodec::<f32, BigEndian>::encode_unchecked(
12.5,
&mut output,
2
)
);
assert_eq!(
8,
BinaryCodec::<f64, LittleEndian>::encode_unchecked(
-25.25,
&mut output,
6
)
);
}
assert_decoded_eq((0x7f, 1), unsafe {
BinaryCodec::<u8, LittleEndian>::decode_unchecked(&output, 0)
});
assert_decoded_eq((-1, 1), unsafe {
BinaryCodec::<i8, BigEndian>::decode_unchecked(&output, 1)
});
assert_decoded_eq((12.5, 4), unsafe {
BinaryCodec::<f32, BigEndian>::decode_unchecked(&output, 2)
});
assert_decoded_eq((-25.25, 8), unsafe {
BinaryCodec::<f64, LittleEndian>::decode_unchecked(&output, 6)
});
}