q_compress 0.3.0

Good data compression for numerical sequences
Documentation
use std::fmt::{Display, Formatter};
use std::fmt;

use crate::bits;
use crate::types::{NumberLike, UnsignedLike};

#[derive(Clone, Copy, Debug, Default)]
pub struct PrefixDecompressionInfo<T> where T: NumberLike {
  pub lower: T,
  pub upper: T,
  pub k: u32,
  pub run_len_jumpstart: Option<usize>,
}

impl<T> PrefixDecompressionInfo<T> where T: NumberLike {
  pub fn new() -> Self {
    PrefixDecompressionInfo {
      ..Default::default()
    }
  }
}

impl<T> From<&Prefix<T>> for PrefixDecompressionInfo<T> where T: NumberLike {
  fn from(p: &Prefix<T>) -> Self {
    PrefixDecompressionInfo {
      lower: p.lower,
      upper: p.upper,
      k: p.k,
      run_len_jumpstart: p.run_len_jumpstart,
    }
  }
}

#[derive(Clone, Debug)]
pub struct Prefix<T> where T: NumberLike {
  pub val: Vec<bool>,
  pub lower: T,
  pub upper: T,
  pub k: u32,
  pub only_k_bits_lower: T::Diff,
  pub only_k_bits_upper: T::Diff,
  pub run_len_jumpstart: Option<usize>,
}

// In Prefix and PrefixIntermediate, lower and upper are always inclusive.
// This allows handling extremal values.
impl<T> Prefix<T> where T: NumberLike {
  pub fn from_intermediate_and_diff(intermediate: &PrefixIntermediate<T>,) -> Prefix<T> {
    Self::new(
      intermediate.val.clone(),
      intermediate.lower,
      intermediate.upper,
      intermediate.run_len_jumpstart,
    )
  }

  pub fn new(val: Vec<bool>, lower: T, upper: T, run_len_jumpstart: Option<usize>) -> Prefix<T> {
    let diff = T::offset_diff(upper, lower);
    let k = (diff.to_f64() + 1.0).log2().floor() as u32;
    let only_k_bits_upper = if k == T::Diff::BITS {
      T::Diff::MAX
    } else {
      (T::Diff::ONE << k) - T::Diff::ONE
    };
    let only_k_bits_lower = diff - only_k_bits_upper;

    Prefix {
      val,
      lower,
      upper,
      k,
      only_k_bits_lower,
      only_k_bits_upper,
      run_len_jumpstart,
    }
  }
}

impl<T> Display for Prefix<T> where T: NumberLike {
  fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
    let reps_info = match self.run_len_jumpstart {
      None => "".to_string(),
      Some(jumpstart) => format!(" (>={} run length bits)", jumpstart)
    };

    write!(
      f,
      "{}: {} to {}{}",
      bits::bits_to_string(&self.val),
      self.lower,
      self.upper,
      reps_info,
    )
  }
}

#[derive(Clone, Debug, PartialEq, Eq)]
pub struct PrefixIntermediate<T> {
  pub weight: u64,
  pub lower: T,
  pub upper: T,
  pub val: Vec<bool>,
  pub run_len_jumpstart: Option<usize>,
}

impl<T> PrefixIntermediate<T> {
  pub fn new(weight: u64, lower: T, upper: T, run_len_jumpstart: Option<usize>) -> PrefixIntermediate<T> {
    PrefixIntermediate {
      weight,
      lower,
      upper,
      val: Vec::new(),
      run_len_jumpstart,
    }
  }
}