f15fae822e
The signed LEB128 decoding function used a hardcoded constant of 64 instead of the number of bits in the type of integer being decoded, which resulted in incorrect results for some inputs. Fix this, make the decoding more consistent with the unsigned version, and increase the LEB128 encoding and decoding test coverage.
95 lines
3.5 KiB
Rust
95 lines
3.5 KiB
Rust
#![feature(int_bits_const)]
|
|
#![feature(maybe_uninit_slice)]
|
|
#![feature(maybe_uninit_uninit_array)]
|
|
|
|
use rustc_serialize::leb128::*;
|
|
use std::mem::MaybeUninit;
|
|
|
|
macro_rules! impl_test_unsigned_leb128 {
|
|
($test_name:ident, $write_fn_name:ident, $read_fn_name:ident, $int_ty:ident) => {
|
|
#[test]
|
|
fn $test_name() {
|
|
// Test 256 evenly spaced values of integer range,
|
|
// integer max value, and some "random" numbers.
|
|
let mut values = Vec::new();
|
|
|
|
let increment = (1 as $int_ty) << ($int_ty::BITS - 8);
|
|
values.extend((0..256).map(|i| $int_ty::MIN + i * increment));
|
|
|
|
values.push($int_ty::MAX);
|
|
|
|
values.extend(
|
|
(-500..500).map(|i| (i as $int_ty).wrapping_mul(0x12345789ABCDEFu64 as $int_ty)),
|
|
);
|
|
|
|
let mut stream = Vec::new();
|
|
|
|
for &x in &values {
|
|
let mut buf = MaybeUninit::uninit_array();
|
|
stream.extend($write_fn_name(&mut buf, x));
|
|
}
|
|
|
|
let mut position = 0;
|
|
for &expected in &values {
|
|
let (actual, bytes_read) = $read_fn_name(&stream[position..]);
|
|
assert_eq!(expected, actual);
|
|
position += bytes_read;
|
|
}
|
|
assert_eq!(stream.len(), position);
|
|
}
|
|
};
|
|
}
|
|
|
|
impl_test_unsigned_leb128!(test_u16_leb128, write_u16_leb128, read_u16_leb128, u16);
|
|
impl_test_unsigned_leb128!(test_u32_leb128, write_u32_leb128, read_u32_leb128, u32);
|
|
impl_test_unsigned_leb128!(test_u64_leb128, write_u64_leb128, read_u64_leb128, u64);
|
|
impl_test_unsigned_leb128!(test_u128_leb128, write_u128_leb128, read_u128_leb128, u128);
|
|
impl_test_unsigned_leb128!(test_usize_leb128, write_usize_leb128, read_usize_leb128, usize);
|
|
|
|
macro_rules! impl_test_signed_leb128 {
|
|
($test_name:ident, $write_fn_name:ident, $read_fn_name:ident, $int_ty:ident) => {
|
|
#[test]
|
|
fn $test_name() {
|
|
// Test 256 evenly spaced values of integer range,
|
|
// integer max value, and some "random" numbers.
|
|
let mut values = Vec::new();
|
|
|
|
let mut value = $int_ty::MIN;
|
|
let increment = (1 as $int_ty) << ($int_ty::BITS - 8);
|
|
|
|
for _ in 0..256 {
|
|
values.push(value);
|
|
// The addition in the last loop iteration overflows.
|
|
value = value.wrapping_add(increment);
|
|
}
|
|
|
|
values.push($int_ty::MAX);
|
|
|
|
values.extend(
|
|
(-500..500).map(|i| (i as $int_ty).wrapping_mul(0x12345789ABCDEFi64 as $int_ty)),
|
|
);
|
|
|
|
let mut stream = Vec::new();
|
|
|
|
for &x in &values {
|
|
let mut buf = MaybeUninit::uninit_array();
|
|
stream.extend($write_fn_name(&mut buf, x));
|
|
}
|
|
|
|
let mut position = 0;
|
|
for &expected in &values {
|
|
let (actual, bytes_read) = $read_fn_name(&stream[position..]);
|
|
assert_eq!(expected, actual);
|
|
position += bytes_read;
|
|
}
|
|
assert_eq!(stream.len(), position);
|
|
}
|
|
};
|
|
}
|
|
|
|
impl_test_signed_leb128!(test_i16_leb128, write_i16_leb128, read_i16_leb128, i16);
|
|
impl_test_signed_leb128!(test_i32_leb128, write_i32_leb128, read_i32_leb128, i32);
|
|
impl_test_signed_leb128!(test_i64_leb128, write_i64_leb128, read_i64_leb128, i64);
|
|
impl_test_signed_leb128!(test_i128_leb128, write_i128_leb128, read_i128_leb128, i128);
|
|
impl_test_signed_leb128!(test_isize_leb128, write_isize_leb128, read_isize_leb128, isize);
|