use std::{io::Read, marker::PhantomData};
use bytes::BytesMut;
use crate::{
encoding::{rle::GenericRle, util::try_read_u8, PrimitiveValueEncoder},
error::{OutOfSpecSnafu, Result},
memory::EstimateMemory,
};
use self::{
delta::{read_delta_values, write_fixed_delta, write_varying_delta},
direct::{read_direct_values, write_direct},
patched_base::{read_patched_base, write_patched_base},
short_repeat::{read_short_repeat_values, write_short_repeat},
};
use super::{util::calculate_percentile_bits, EncodingSign, NInt, VarintSerde};
mod delta;
mod direct;
mod patched_base;
mod short_repeat;
const MAX_RUN_LENGTH: usize = 512;
const SHORT_REPEAT_MIN_LENGTH: usize = 3;
const SHORT_REPEAT_MAX_LENGTH: usize = 10;
const BASE_VALUE_LIMIT: i64 = 1 << 56;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
enum EncodingType {
ShortRepeat,
Direct,
PatchedBase,
Delta,
}
impl EncodingType {
#[inline]
fn from_header(header: u8) -> Self {
match header & 0b_1100_0000 {
0b_1100_0000 => Self::Delta,
0b_1000_0000 => Self::PatchedBase,
0b_0100_0000 => Self::Direct,
0b_0000_0000 => Self::ShortRepeat,
_ => unreachable!(),
}
}
#[inline]
fn to_header(self) -> u8 {
match self {
EncodingType::Delta => 0b_1100_0000,
EncodingType::PatchedBase => 0b_1000_0000,
EncodingType::Direct => 0b_0100_0000,
EncodingType::ShortRepeat => 0b_0000_0000,
}
}
}
pub struct RleV2Decoder<N: NInt, R: Read, S: EncodingSign> {
reader: R,
decoded_ints: Vec<N>,
current_head: usize,
deltas: Vec<i64>,
sign: PhantomData<S>,
}
impl<N: NInt, R: Read, S: EncodingSign> RleV2Decoder<N, R, S> {
pub fn new(reader: R) -> Self {
Self {
reader,
decoded_ints: Vec::with_capacity(MAX_RUN_LENGTH),
current_head: 0,
deltas: Vec::with_capacity(MAX_RUN_LENGTH),
sign: Default::default(),
}
}
}
impl<N: NInt, R: Read, S: EncodingSign> GenericRle<N> for RleV2Decoder<N, R, S> {
fn advance(&mut self, n: usize) {
self.current_head += n;
}
fn available(&self) -> &[N] {
&self.decoded_ints[self.current_head..]
}
fn decode_batch(&mut self) -> Result<()> {
self.current_head = 0;
self.decoded_ints.clear();
let header = match try_read_u8(&mut self.reader)? {
Some(byte) => byte,
None => {
return OutOfSpecSnafu {
msg: "not enough values to decode in RLE v2",
}
.fail();
}
};
match EncodingType::from_header(header) {
EncodingType::ShortRepeat => read_short_repeat_values::<_, _, S>(
&mut self.reader,
&mut self.decoded_ints,
header,
)?,
EncodingType::Direct => {
read_direct_values::<_, _, S>(&mut self.reader, &mut self.decoded_ints, header)?
}
EncodingType::PatchedBase => {
read_patched_base::<_, _, S>(&mut self.reader, &mut self.decoded_ints, header)?
}
EncodingType::Delta => read_delta_values::<_, _, S>(
&mut self.reader,
&mut self.decoded_ints,
&mut self.deltas,
header,
)?,
}
Ok(())
}
fn skip_values(&mut self, n: usize) -> Result<()> {
let mut remaining = n;
let available = self.decoded_ints.len() - self.current_head;
if available >= remaining {
self.advance(remaining);
return Ok(());
}
self.advance(available);
remaining -= available;
while remaining > 0 {
self.decode_batch()?;
let decoded_count = self.decoded_ints.len();
let to_skip = decoded_count.min(remaining);
self.advance(to_skip);
remaining -= to_skip;
}
Ok(())
}
}
struct DeltaEncodingCheckResult<N: NInt> {
base_value: N,
min: N,
max: N,
first_delta: i64,
max_delta: i64,
is_monotonic: bool,
is_fixed_delta: bool,
adjacent_deltas: Vec<i64>,
}
fn delta_encoding_check<N: NInt>(literals: &[N]) -> DeltaEncodingCheckResult<N> {
let base_value = literals[0];
let mut min = base_value.min(literals[1]);
let mut max = base_value.max(literals[1]);
let first_delta = literals[1].as_i64().saturating_sub(base_value.as_i64());
let mut current_delta;
let mut max_delta = 0;
let mut is_increasing = first_delta.is_positive();
let mut is_decreasing = first_delta.is_negative();
let mut is_fixed_delta = true;
let mut adjacent_deltas = vec![];
for i in 2..literals.len() {
let l1 = literals[i];
let l0 = literals[i - 1];
min = min.min(l1);
max = max.max(l1);
current_delta = l1.as_i64().saturating_sub(l0.as_i64());
is_increasing &= current_delta >= 0;
is_decreasing &= current_delta <= 0;
is_fixed_delta &= current_delta == first_delta;
let current_delta = current_delta.saturating_abs();
adjacent_deltas.push(current_delta);
max_delta = max_delta.max(current_delta);
}
let is_monotonic = is_increasing || is_decreasing;
DeltaEncodingCheckResult {
base_value,
min,
max,
first_delta,
max_delta,
is_monotonic,
is_fixed_delta,
adjacent_deltas,
}
}
#[derive(Debug, Clone, Eq, PartialEq, Default)]
enum RleV2EncodingState<N: NInt> {
#[default]
Empty,
One(N),
FixedRun { value: N, count: usize },
VariableRun { literals: Vec<N> },
}
pub struct RleV2Encoder<N: NInt, S: EncodingSign> {
data: BytesMut,
state: RleV2EncodingState<N>,
phantom: PhantomData<S>,
}
impl<N: NInt, S: EncodingSign> RleV2Encoder<N, S> {
fn process_value(&mut self, value: N) {
match &mut self.state {
RleV2EncodingState::Empty => {
self.state = RleV2EncodingState::One(value);
}
RleV2EncodingState::One(one_value) => {
if value == *one_value {
self.state = RleV2EncodingState::FixedRun { value, count: 2 };
} else {
let mut literals = Vec::with_capacity(MAX_RUN_LENGTH);
literals.push(*one_value);
literals.push(value);
self.state = RleV2EncodingState::VariableRun { literals };
}
}
RleV2EncodingState::FixedRun {
value: fixed_value,
count,
} => {
if value == *fixed_value {
*count += 1;
if *count == MAX_RUN_LENGTH {
write_fixed_delta::<_, S>(&mut self.data, value, 0, *count - 2);
self.state = RleV2EncodingState::Empty;
}
} else {
match count {
2 => {
let mut literals = Vec::with_capacity(MAX_RUN_LENGTH);
literals.push(*fixed_value);
literals.push(*fixed_value);
literals.push(value);
self.state = RleV2EncodingState::VariableRun { literals };
}
SHORT_REPEAT_MIN_LENGTH..=SHORT_REPEAT_MAX_LENGTH => {
write_short_repeat::<_, S>(&mut self.data, *fixed_value, *count);
self.state = RleV2EncodingState::One(value);
}
_ => {
write_fixed_delta::<_, S>(&mut self.data, *fixed_value, 0, *count - 2);
self.state = RleV2EncodingState::One(value);
}
}
}
}
RleV2EncodingState::VariableRun { literals } => {
let length = literals.len();
let last_value = literals[length - 1];
let second_last_value = literals[length - 2];
if value == last_value && value == second_last_value {
literals.truncate(literals.len() - 2);
determine_variable_run_encoding::<_, S>(&mut self.data, literals);
self.state = RleV2EncodingState::FixedRun { value, count: 3 };
} else {
literals.push(value);
if literals.len() == MAX_RUN_LENGTH {
determine_variable_run_encoding::<_, S>(&mut self.data, literals);
self.state = RleV2EncodingState::Empty;
}
}
}
}
}
fn flush(&mut self) {
let state = std::mem::take(&mut self.state);
match state {
RleV2EncodingState::Empty => {}
RleV2EncodingState::One(value) => {
let value = S::zigzag_encode(value);
write_direct(&mut self.data, &[value], Some(value));
}
RleV2EncodingState::FixedRun { value, count: 2 } => {
let value = S::zigzag_encode(value);
write_direct(&mut self.data, &[value, value], Some(value));
}
RleV2EncodingState::FixedRun { value, count } if count <= SHORT_REPEAT_MAX_LENGTH => {
write_short_repeat::<_, S>(&mut self.data, value, count);
}
RleV2EncodingState::FixedRun { value, count } => {
write_fixed_delta::<_, S>(&mut self.data, value, 0, count - 2);
}
RleV2EncodingState::VariableRun { mut literals } => {
determine_variable_run_encoding::<_, S>(&mut self.data, &mut literals);
}
}
}
}
impl<N: NInt, S: EncodingSign> EstimateMemory for RleV2Encoder<N, S> {
fn estimate_memory_size(&self) -> usize {
self.data.len()
}
}
impl<N: NInt, S: EncodingSign> PrimitiveValueEncoder<N> for RleV2Encoder<N, S> {
fn new() -> Self {
Self {
data: BytesMut::new(),
state: RleV2EncodingState::Empty,
phantom: Default::default(),
}
}
fn write_one(&mut self, value: N) {
self.process_value(value);
}
fn take_inner(&mut self) -> bytes::Bytes {
self.flush();
std::mem::take(&mut self.data).into()
}
}
fn determine_variable_run_encoding<N: NInt, S: EncodingSign>(
writer: &mut BytesMut,
literals: &mut [N],
) {
if literals.len() <= SHORT_REPEAT_MIN_LENGTH {
for v in literals.iter_mut() {
*v = S::zigzag_encode(*v);
}
write_direct(writer, literals, None);
return;
}
let DeltaEncodingCheckResult {
base_value,
min,
max,
first_delta,
max_delta,
is_monotonic,
is_fixed_delta,
adjacent_deltas,
} = delta_encoding_check(literals);
if max.checked_sub(&min).is_none() {
for v in literals.iter_mut() {
*v = S::zigzag_encode(*v);
}
write_direct(writer, literals, None);
return;
}
if is_fixed_delta {
write_fixed_delta::<_, S>(writer, literals[0], first_delta, literals.len() - 2);
return;
}
if first_delta != 0 && is_monotonic {
write_varying_delta::<_, S>(writer, base_value, first_delta, max_delta, &adjacent_deltas);
return;
}
let min = min.as_i64();
if min.abs() >= BASE_VALUE_LIMIT && min != i64::MIN {
for v in literals.iter_mut() {
*v = S::zigzag_encode(*v);
}
write_direct(writer, literals, None);
return;
}
let zigzag_literals = literals
.iter()
.map(|&v| S::zigzag_encode(v))
.collect::<Vec<_>>();
let zigzagged_90_percentile_bit_width = calculate_percentile_bits(&zigzag_literals, 0.90);
let zigzagged_100_percentile_bit_width = calculate_percentile_bits(&zigzag_literals, 1.00);
if (zigzagged_100_percentile_bit_width.saturating_sub(zigzagged_90_percentile_bit_width)) <= 1 {
write_direct(writer, &zigzag_literals, None);
return;
}
let mut max_data_value = 0;
let mut base_reduced_literals = vec![];
for l in literals.iter() {
let base_reduced_literal = l.as_i64() - min;
base_reduced_literals.push(base_reduced_literal);
max_data_value = max_data_value.max(base_reduced_literal);
}
let base_reduced_literals_max_bit_width = max_data_value.bits_used();
let base_reduced_literals_95th_percentile_bit_width =
calculate_percentile_bits(&base_reduced_literals, 0.95);
if base_reduced_literals_max_bit_width != base_reduced_literals_95th_percentile_bit_width {
write_patched_base(
writer,
&mut base_reduced_literals,
min,
base_reduced_literals_max_bit_width,
base_reduced_literals_95th_percentile_bit_width,
);
} else {
write_direct(writer, &zigzag_literals, None);
}
}
#[cfg(test)]
mod tests {
use std::io::Cursor;
use arrow::datatypes::ToByteSlice;
use proptest::prelude::*;
use crate::encoding::{
integer::{SignedEncoding, UnsignedEncoding},
PrimitiveValueDecoder,
};
use super::*;
fn test_helper<S: EncodingSign>(data: &[u8], expected: &[i64]) {
let mut reader = RleV2Decoder::<i64, _, S>::new(Cursor::new(data));
let mut actual = vec![0; expected.len()];
reader.decode(&mut actual).unwrap();
assert_eq!(actual, expected);
}
#[test]
fn writer_test_patched_base() {
let mut literals = [
2030, 2000, 2020, 1000000, 2040, 2050, 2060, 2070, 2080, 2090, 2100, 2110, 2120, 2130,
2140, 2150, 2160, 2170, 2180, 2190,
];
let expected = [
0x8e, 0x13, 0x2b, 0x21, 0x07, 0xd0, 0x1e, 0x00, 0x14, 0x70, 0x28, 0x32, 0x3c, 0x46,
0x50, 0x5a, 0x64, 0x6e, 0x78, 0x82, 0x8c, 0x96, 0xa0, 0xaa, 0xb4, 0xbe, 0xfc, 0xe8,
];
let mut writer = RleV2Encoder::<i64, UnsignedEncoding>::new();
determine_variable_run_encoding::<i64, UnsignedEncoding>(&mut writer.data, &mut literals);
assert_eq!(writer.data.to_byte_slice(), expected);
}
#[test]
fn writer_test_choose_direct_over_patched_base() {
let mut literals = [0, 7, 6, 4, 5, 7, 0, 5, 6, 1, 4, 6, 5, 5, 3, 6, 7, 31, 17, 3];
let expected = [
0x4e, 0x13, 0, 7, 6, 4, 5, 7, 0, 5, 6, 1, 4, 6, 5, 5, 3, 6, 7, 31, 17, 3,
];
let mut writer = RleV2Encoder::<i64, UnsignedEncoding>::new();
determine_variable_run_encoding::<i64, UnsignedEncoding>(&mut writer.data, &mut literals);
assert_eq!(writer.data.to_byte_slice(), expected);
}
#[test]
fn reader_test() {
let data = [2, 1, 64, 5, 80, 1, 1];
let expected = [1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 1, 1];
test_helper::<UnsignedEncoding>(&data, &expected);
let data = [0x5e, 0x03, 0x5c, 0xa1, 0xab, 0x1e, 0xde, 0xad, 0xbe, 0xef];
let expected = [23713, 43806, 57005, 48879];
test_helper::<UnsignedEncoding>(&data, &expected);
let data = [
102, 9, 0, 126, 224, 7, 208, 0, 126, 79, 66, 64, 0, 127, 128, 8, 2, 0, 128, 192, 8, 22,
0, 130, 0, 8, 42,
];
let expected = [
2030, 2000, 2020, 1000000, 2040, 2050, 2060, 2070, 2080, 2090,
];
test_helper::<UnsignedEncoding>(&data, &expected);
let data = [196, 9, 2, 2, 74, 40, 166];
let expected = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29];
test_helper::<UnsignedEncoding>(&data, &expected);
let data = [0xc6, 0x09, 0x02, 0x02, 0x22, 0x42, 0x42, 0x46];
let expected = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29];
test_helper::<UnsignedEncoding>(&data, &expected);
let data = [7, 1];
let expected = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1];
test_helper::<UnsignedEncoding>(&data, &expected);
}
#[test]
fn short_repeat() {
let data = [0x0a, 0x27, 0x10];
let expected = [10000, 10000, 10000, 10000, 10000];
test_helper::<UnsignedEncoding>(&data, &expected);
}
#[test]
fn direct() {
let data = [0x5e, 0x03, 0x5c, 0xa1, 0xab, 0x1e, 0xde, 0xad, 0xbe, 0xef];
let expected = [23713, 43806, 57005, 48879];
test_helper::<UnsignedEncoding>(&data, &expected);
}
#[test]
fn direct_signed() {
let data = [110, 3, 0, 185, 66, 1, 86, 60, 1, 189, 90, 1, 125, 222];
let expected = [23713, 43806, 57005, 48879];
test_helper::<SignedEncoding>(&data, &expected);
}
#[test]
fn delta() {
let data = [0xc6, 0x09, 0x02, 0x02, 0x22, 0x42, 0x42, 0x46];
let expected = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29];
test_helper::<UnsignedEncoding>(&data, &expected);
}
#[test]
fn patched_base() {
let data = [
0x8e, 0x09, 0x2b, 0x21, 0x07, 0xd0, 0x1e, 0x00, 0x14, 0x70, 0x28, 0x32, 0x3c, 0x46,
0x50, 0x5a, 0xfc, 0xe8,
];
let expected = [
2030, 2000, 2020, 1000000, 2040, 2050, 2060, 2070, 2080, 2090,
];
test_helper::<UnsignedEncoding>(&data, &expected);
}
#[test]
fn patched_base_1() {
let data = vec![
144, 109, 4, 164, 141, 16, 131, 194, 0, 240, 112, 64, 60, 84, 24, 3, 193, 201, 128,
120, 60, 33, 4, 244, 3, 193, 192, 224, 128, 56, 32, 15, 22, 131, 129, 225, 0, 112, 84,
86, 14, 8, 106, 193, 192, 228, 160, 64, 32, 14, 213, 131, 193, 192, 240, 121, 124, 30,
18, 9, 132, 67, 0, 224, 120, 60, 28, 14, 32, 132, 65, 192, 240, 160, 56, 61, 91, 7, 3,
193, 192, 240, 120, 76, 29, 23, 7, 3, 220, 192, 240, 152, 60, 52, 15, 7, 131, 129, 225,
0, 144, 56, 30, 14, 44, 140, 129, 194, 224, 120, 0, 28, 15, 8, 6, 129, 198, 144, 128,
104, 36, 27, 11, 38, 131, 33, 48, 224, 152, 60, 111, 6, 183, 3, 112, 0, 1, 78, 5, 46,
2, 1, 1, 141, 3, 1, 1, 138, 22, 0, 65, 1, 4, 0, 225, 16, 209, 192, 4, 16, 8, 36, 16, 3,
48, 1, 3, 13, 33, 0, 176, 0, 1, 94, 18, 0, 68, 0, 33, 1, 143, 0, 1, 7, 93, 0, 25, 0, 5,
0, 2, 0, 4, 0, 1, 0, 1, 0, 2, 0, 16, 0, 1, 11, 150, 0, 3, 0, 1, 0, 1, 99, 157, 0, 1,
140, 54, 0, 162, 1, 130, 0, 16, 112, 67, 66, 0, 2, 4, 0, 0, 224, 0, 1, 0, 16, 64, 16,
91, 198, 1, 2, 0, 32, 144, 64, 0, 12, 2, 8, 24, 0, 64, 0, 1, 0, 0, 8, 48, 51, 128, 0,
2, 12, 16, 32, 32, 71, 128, 19, 76,
];
let expected = vec![
20, 2, 3, 2, 1, 3, 17, 71, 35, 2, 1, 139, 2, 2, 3, 1783, 475, 2, 1, 1, 3, 1, 3, 2, 32,
1, 2, 3, 1, 8, 30, 1, 3, 414, 1, 1, 135, 3, 3, 1, 414, 2, 1, 2, 2, 594, 2, 5, 6, 4, 11,
1, 2, 2, 1, 1, 52, 4, 1, 2, 7, 1, 17, 334, 1, 2, 1, 2, 2, 6, 1, 266, 1, 2, 217, 2, 6,
2, 13, 2, 2, 1, 2, 3, 5, 1, 2, 1, 7244, 11813, 1, 33, 2, -13, 1, 2, 3, 13, 1, 92, 3,
13, 5, 14, 9, 141, 12, 6, 15, 25, -1, -1, -1, 23, 1, -1, -1, -71, -2, -1, -1, -1, -1,
2, 1, 4, 34, 5, 78, 8, 1, 2, 2, 1, 9, 10, 2, 1, 4, 13, 1, 5, 4, 4, 19, 5, -1, -1, -1,
34, -17, -200, -1, -943, -13, -3, 1, 2, -1, -1, 1, 8, -1, 1483, -2, -1, -1, -12751, -1,
-1, -1, 66, 1, 3, 8, 131, 14, 5, 1, 2, 2, 1, 1, 8, 1, 1, 2, 1, 5, 9, 2, 3, 112, 13, 2,
2, 1, 5, 10, 3, 1, 1, 13, 2, 3, 4, 1, 3, 1, 1, 2, 1, 1, 2, 4, 2, 207, 1, 1, 2, 4, 3, 3,
2, 2, 16,
];
test_helper::<SignedEncoding>(&data, &expected);
}
fn roundtrip_helper<N: NInt, S: EncodingSign>(values: &[N]) -> Result<Vec<N>> {
let mut writer = RleV2Encoder::<N, S>::new();
writer.write_slice(values);
let data = writer.take_inner();
let mut reader = RleV2Decoder::<N, _, S>::new(Cursor::new(data));
let mut actual = vec![N::zero(); values.len()];
reader.decode(&mut actual).unwrap();
Ok(actual)
}
#[test]
fn test_skip_values_short_repeat() -> Result<()> {
let data = [0x0a, 0x27, 0x10];
let mut decoder = RleV2Decoder::<i64, _, UnsignedEncoding>::new(Cursor::new(&data));
let mut batch = vec![0; 2];
decoder.decode(&mut batch)?;
assert_eq!(batch, vec![10000, 10000]);
decoder.skip(2)?;
let mut batch = vec![0; 1];
decoder.decode(&mut batch)?;
assert_eq!(batch, vec![10000]);
Ok(())
}
#[test]
fn test_skip_values_entire_block() -> Result<()> {
let mut encoder1 = RleV2Encoder::<_, UnsignedEncoding>::new();
for _ in 0..5 {
encoder1.write_one(100);
}
encoder1.flush();
let data1 = encoder1.take_inner();
let mut encoder2 = RleV2Encoder::<_, UnsignedEncoding>::new();
for _ in 0..5 {
encoder2.write_one(200);
}
encoder2.flush();
let data2 = encoder2.take_inner();
let mut combined = Vec::new();
combined.extend_from_slice(&data1);
combined.extend_from_slice(&data2);
let mut decoder = RleV2Decoder::<i64, _, UnsignedEncoding>::new(Cursor::new(&combined));
decoder.skip(5)?;
let mut batch = vec![0; 3];
decoder.decode(&mut batch)?;
assert_eq!(batch, vec![200, 200, 200]);
Ok(())
}
#[test]
fn test_skip_values_across_blocks() -> Result<()> {
let mut encoder = RleV2Encoder::<_, SignedEncoding>::new();
for _ in 0..5 {
encoder.write_one(100);
}
encoder.flush();
for _ in 0..5 {
encoder.write_one(200);
}
encoder.flush();
for _ in 0..5 {
encoder.write_one(300);
}
encoder.flush();
let data = encoder.take_inner();
let mut decoder = RleV2Decoder::<i32, _, SignedEncoding>::new(Cursor::new(&data));
decoder.skip(7)?;
let mut batch = vec![0; 1];
decoder.decode(&mut batch)?;
assert_eq!(batch, vec![200]);
decoder.skip(2)?;
let mut batch = vec![0; 3];
decoder.decode(&mut batch)?;
assert_eq!(batch, vec![300, 300, 300]);
Ok(())
}
#[test]
fn test_skip_values_direct_encoding() -> Result<()> {
let data = [0x5e, 0x03, 0x5c, 0xa1, 0xab, 0x1e, 0xde, 0xad, 0xbe, 0xef];
let mut decoder = RleV2Decoder::<i64, _, UnsignedEncoding>::new(Cursor::new(&data));
let mut batch = vec![0; 2];
decoder.decode(&mut batch)?;
assert_eq!(batch, vec![23713, 43806]);
decoder.skip(1)?;
let mut batch = vec![0; 1];
decoder.decode(&mut batch)?;
assert_eq!(batch, vec![48879]);
Ok(())
}
#[test]
fn test_skip_values_delta_encoding() -> Result<()> {
let data = [0xc6, 0x09, 0x02, 0x02, 0x22, 0x42, 0x42, 0x46];
let mut decoder = RleV2Decoder::<i64, _, UnsignedEncoding>::new(Cursor::new(&data));
decoder.skip(5)?;
let mut batch = vec![0; 3];
decoder.decode(&mut batch)?;
assert_eq!(batch, vec![13, 17, 19]);
Ok(())
}
#[test]
fn test_skip_values_patched_base() -> Result<()> {
let data = [
0x8e, 0x09, 0x2b, 0x21, 0x07, 0xd0, 0x1e, 0x00, 0x14, 0x70, 0x28, 0x32, 0x3c, 0x46,
0x50, 0x5a, 0xfc, 0xe8,
];
let mut decoder = RleV2Decoder::<i64, _, UnsignedEncoding>::new(Cursor::new(&data));
decoder.skip(3)?;
let mut batch = vec![0; 1];
decoder.decode(&mut batch)?;
assert_eq!(batch, vec![1000000]);
decoder.skip(2)?;
let mut batch = vec![0; 3];
decoder.decode(&mut batch)?;
assert_eq!(batch, vec![2060, 2070, 2080]);
Ok(())
}
#[test]
fn test_skip_all_values() -> Result<()> {
let mut encoder = RleV2Encoder::<_, SignedEncoding>::new();
for _ in 0..5 {
encoder.write_one(10);
}
encoder.flush();
for _ in 0..5 {
encoder.write_one(20);
}
encoder.flush();
let data = encoder.take_inner();
let mut decoder = RleV2Decoder::<i32, _, SignedEncoding>::new(Cursor::new(&data));
decoder.skip(10)?;
let mut batch = vec![0; 1];
let result = decoder.decode(&mut batch);
assert!(result.is_err() || batch[0] == 0);
Ok(())
}
proptest! {
#[test]
fn roundtrip_i16(values in prop::collection::vec(any::<i16>(), 1..1_000)) {
let out = roundtrip_helper::<_, SignedEncoding>(&values)?;
prop_assert_eq!(out, values);
}
#[test]
fn roundtrip_i32(values in prop::collection::vec(any::<i32>(), 1..1_000)) {
let out = roundtrip_helper::<_, SignedEncoding>(&values)?;
prop_assert_eq!(out, values);
}
#[test]
fn roundtrip_i64(values in prop::collection::vec(any::<i64>(), 1..1_000)) {
let out = roundtrip_helper::<_, SignedEncoding>(&values)?;
prop_assert_eq!(out, values);
}
#[test]
fn roundtrip_i64_unsigned(values in prop::collection::vec(0..=i64::MAX, 1..1_000)) {
let out = roundtrip_helper::<_, UnsignedEncoding>(&values)?;
prop_assert_eq!(out, values);
}
}
}