use std::{
fmt,
io::Read,
ops::{BitOrAssign, ShlAssign},
};
use num::traits::{CheckedShl, WrappingAdd};
use num::{PrimInt, Signed};
use rle_v1::RleV1Decoder;
use rle_v2::RleV2Decoder;
use snafu::ResultExt;
use util::{
get_closest_aligned_bit_width, signed_msb_decode, signed_zigzag_decode, signed_zigzag_encode,
};
use crate::error::{IoSnafu, Result};
use super::PrimitiveValueDecoder;
pub mod rle_v1;
pub mod rle_v2;
mod util;
pub use util::read_varint_zigzagged;
#[derive(Debug, Clone, Copy)]
pub enum RleVersion {
V1,
V2,
}
pub fn get_signed_int_decoder<N: NInt>(
reader: impl Read + Send + 'static,
rle_version: RleVersion,
) -> Box<dyn PrimitiveValueDecoder<N> + Send> {
match rle_version {
RleVersion::V1 => Box::new(RleV1Decoder::<N, _, SignedEncoding>::new(reader)),
RleVersion::V2 => Box::new(RleV2Decoder::<N, _, SignedEncoding>::new(reader)),
}
}
pub fn get_unsigned_int_decoder<N: NInt>(
reader: impl Read + Send + 'static,
rle_version: RleVersion,
) -> Box<dyn PrimitiveValueDecoder<N> + Send> {
match rle_version {
RleVersion::V1 => Box::new(RleV1Decoder::<N, _, UnsignedEncoding>::new(reader)),
RleVersion::V2 => Box::new(RleV2Decoder::<N, _, UnsignedEncoding>::new(reader)),
}
}
pub trait EncodingSign: Send + 'static {
fn zigzag_decode<N: VarintSerde>(v: N) -> N;
fn zigzag_encode<N: VarintSerde>(v: N) -> N;
fn decode_signed_msb<N: NInt>(v: N, encoded_byte_size: usize) -> N;
}
pub struct SignedEncoding;
impl EncodingSign for SignedEncoding {
#[inline]
fn zigzag_decode<N: VarintSerde>(v: N) -> N {
signed_zigzag_decode(v)
}
#[inline]
fn zigzag_encode<N: VarintSerde>(v: N) -> N {
signed_zigzag_encode(v)
}
#[inline]
fn decode_signed_msb<N: NInt>(v: N, encoded_byte_size: usize) -> N {
signed_msb_decode(v, encoded_byte_size)
}
}
pub struct UnsignedEncoding;
impl EncodingSign for UnsignedEncoding {
#[inline]
fn zigzag_decode<N: VarintSerde>(v: N) -> N {
v
}
#[inline]
fn zigzag_encode<N: VarintSerde>(v: N) -> N {
v
}
#[inline]
fn decode_signed_msb<N: NInt>(v: N, _encoded_byte_size: usize) -> N {
v
}
}
pub trait VarintSerde: PrimInt + CheckedShl + BitOrAssign + Signed + WrappingAdd {
const BYTE_SIZE: usize;
#[inline]
fn bits_used(self) -> usize {
Self::BYTE_SIZE * 8 - self.leading_zeros() as usize
}
fn closest_aligned_bit_width(self) -> usize {
get_closest_aligned_bit_width(self.bits_used())
}
fn from_u8(b: u8) -> Self;
}
pub trait NInt:
VarintSerde + ShlAssign<usize> + fmt::Debug + fmt::Display + fmt::Binary + Send + Sync + 'static
{
type Bytes: AsRef<[u8]> + AsMut<[u8]> + Default + Clone + Copy + fmt::Debug;
#[inline]
fn empty_byte_array() -> Self::Bytes {
Self::Bytes::default()
}
fn from_i64(u: i64) -> Self;
fn from_be_bytes(b: Self::Bytes) -> Self;
fn to_be_bytes(self) -> Self::Bytes;
fn add_i64(self, i: i64) -> Option<Self>;
fn sub_i64(self, i: i64) -> Option<Self>;
fn as_i64(self) -> i64;
fn read_big_endian(reader: &mut impl Read, byte_size: usize) -> Result<Self> {
debug_assert!(
byte_size <= Self::BYTE_SIZE,
"byte_size cannot exceed max byte size of self"
);
let mut buffer = Self::empty_byte_array();
reader
.read_exact(&mut buffer.as_mut()[Self::BYTE_SIZE - byte_size..])
.context(IoSnafu)?;
Ok(Self::from_be_bytes(buffer))
}
}
impl VarintSerde for i16 {
const BYTE_SIZE: usize = 2;
#[inline]
fn from_u8(b: u8) -> Self {
b as Self
}
}
impl VarintSerde for i32 {
const BYTE_SIZE: usize = 4;
#[inline]
fn from_u8(b: u8) -> Self {
b as Self
}
}
impl VarintSerde for i64 {
const BYTE_SIZE: usize = 8;
#[inline]
fn from_u8(b: u8) -> Self {
b as Self
}
}
impl VarintSerde for i128 {
const BYTE_SIZE: usize = 16;
#[inline]
fn from_u8(b: u8) -> Self {
b as Self
}
}
impl NInt for i16 {
type Bytes = [u8; 2];
#[inline]
fn from_i64(i: i64) -> Self {
i as Self
}
#[inline]
fn from_be_bytes(b: Self::Bytes) -> Self {
Self::from_be_bytes(b)
}
#[inline]
fn to_be_bytes(self) -> Self::Bytes {
self.to_be_bytes()
}
#[inline]
fn add_i64(self, i: i64) -> Option<Self> {
self.as_i64().checked_add(i).and_then(|v| v.try_into().ok())
}
#[inline]
fn sub_i64(self, i: i64) -> Option<Self> {
self.as_i64().checked_sub(i).and_then(|v| v.try_into().ok())
}
#[inline]
fn as_i64(self) -> i64 {
self as i64
}
}
impl NInt for i32 {
type Bytes = [u8; 4];
#[inline]
fn from_i64(i: i64) -> Self {
i as Self
}
#[inline]
fn from_be_bytes(b: Self::Bytes) -> Self {
Self::from_be_bytes(b)
}
#[inline]
fn to_be_bytes(self) -> Self::Bytes {
self.to_be_bytes()
}
#[inline]
fn add_i64(self, i: i64) -> Option<Self> {
self.as_i64().checked_add(i).and_then(|v| v.try_into().ok())
}
#[inline]
fn sub_i64(self, i: i64) -> Option<Self> {
self.as_i64().checked_sub(i).and_then(|v| v.try_into().ok())
}
#[inline]
fn as_i64(self) -> i64 {
self as i64
}
}
impl NInt for i64 {
type Bytes = [u8; 8];
#[inline]
fn from_i64(i: i64) -> Self {
i as Self
}
#[inline]
fn from_be_bytes(b: Self::Bytes) -> Self {
Self::from_be_bytes(b)
}
#[inline]
fn to_be_bytes(self) -> Self::Bytes {
self.to_be_bytes()
}
#[inline]
fn add_i64(self, i: i64) -> Option<Self> {
self.checked_add(i)
}
#[inline]
fn sub_i64(self, i: i64) -> Option<Self> {
self.checked_sub(i)
}
#[inline]
fn as_i64(self) -> i64 {
self
}
}