use compression_core::Level;
use mzstd::{
CompressionParams, DecodeLimits, DecoderConfig, EncoderConfig, FrameMode, LdmParams,
LongDistanceMatching,
};
use std::convert::TryFrom;
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct CParameter(CParameterInner);
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
enum CParameterInner {
WindowLog(u32),
HashLog(u32),
ChainLog(u32),
SearchLog(u32),
MinMatch(u32),
TargetLength(u32),
EnableLongDistanceMatching(bool),
LdmHashLog(u32),
LdmMinMatch(u32),
LdmBucketSizeLog(u32),
LdmHashRateLog(u32),
ContentSizeFlag(bool),
ChecksumFlag(bool),
}
impl CParameter {
pub fn quality(level: Level) -> i32 {
const OUR_FASTEST: i32 = 1;
match level {
Level::Fastest => OUR_FASTEST,
Level::Best => mzstd::Level::MAX.get(),
Level::Precise(quality) => {
quality.clamp(mzstd::Level::MIN.get(), mzstd::Level::MAX.get())
}
_ => mzstd::Level::DEFAULT.get(),
}
}
pub fn window_log(value: u32) -> Self {
Self(CParameterInner::WindowLog(value))
}
pub fn hash_log(value: u32) -> Self {
Self(CParameterInner::HashLog(value))
}
pub fn chain_log(value: u32) -> Self {
Self(CParameterInner::ChainLog(value))
}
pub fn search_log(value: u32) -> Self {
Self(CParameterInner::SearchLog(value))
}
pub fn min_match(value: u32) -> Self {
Self(CParameterInner::MinMatch(value))
}
pub fn target_length(value: u32) -> Self {
Self(CParameterInner::TargetLength(value))
}
pub fn enable_long_distance_matching(value: bool) -> Self {
Self(CParameterInner::EnableLongDistanceMatching(value))
}
pub fn ldm_hash_log(value: u32) -> Self {
Self(CParameterInner::LdmHashLog(value))
}
pub fn ldm_min_match(value: u32) -> Self {
Self(CParameterInner::LdmMinMatch(value))
}
pub fn ldm_bucket_size_log(value: u32) -> Self {
Self(CParameterInner::LdmBucketSizeLog(value))
}
pub fn ldm_hash_rate_log(value: u32) -> Self {
Self(CParameterInner::LdmHashRateLog(value))
}
pub fn content_size_flag(value: bool) -> Self {
Self(CParameterInner::ContentSizeFlag(value))
}
pub fn checksum_flag(value: bool) -> Self {
Self(CParameterInner::ChecksumFlag(value))
}
}
pub(crate) fn encoder_config(level: i32, params: &[CParameter]) -> EncoderConfig {
let level = level.clamp(mzstd::Level::MIN.get(), mzstd::Level::MAX.get());
let mut config = EncoderConfig::new().with_level(mzstd::Level::try_from(level).unwrap());
let mut compression = CompressionParams::default();
let mut ldm = LdmParams::default();
let mut ldm_enabled = None;
for param in params {
match param.0 {
CParameterInner::WindowLog(value) => compression = compression.with_window_log(value),
CParameterInner::HashLog(value) => compression = compression.with_hash_log(value),
CParameterInner::ChainLog(value) => compression = compression.with_chain_log(value),
CParameterInner::SearchLog(value) => compression = compression.with_search_log(value),
CParameterInner::MinMatch(value) => compression = compression.with_min_match(value),
CParameterInner::TargetLength(value) => {
compression = compression.with_target_length(value)
}
CParameterInner::EnableLongDistanceMatching(value) => ldm_enabled = Some(value),
CParameterInner::LdmHashLog(value) => ldm = ldm.with_hash_log(value),
CParameterInner::LdmMinMatch(value) => ldm = ldm.with_min_match(value),
CParameterInner::LdmBucketSizeLog(value) => ldm = ldm.with_bucket_size_log(value),
CParameterInner::LdmHashRateLog(value) => ldm = ldm.with_hash_rate_log(value),
CParameterInner::ContentSizeFlag(value) => config = config.with_content_size(value),
CParameterInner::ChecksumFlag(value) => config = config.with_checksum(value),
}
}
let long_distance = match ldm_enabled {
None => LongDistanceMatching::Auto,
Some(false) => LongDistanceMatching::Disabled,
Some(true) => LongDistanceMatching::Enabled(ldm),
};
config
.with_params(compression)
.with_long_distance_matching(long_distance)
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct DParameter(DParameterInner);
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
enum DParameterInner {
WindowLogMax(u32),
}
impl DParameter {
pub fn window_log_max(value: u32) -> Self {
Self(DParameterInner::WindowLogMax(value))
}
}
pub(crate) fn decoder_config(params: &[DParameter]) -> DecoderConfig {
let mut limits = DecodeLimits::DEFAULT;
for param in params {
match param.0 {
DParameterInner::WindowLogMax(0) => limits = DecodeLimits::DEFAULT,
DParameterInner::WindowLogMax(value) => {
let log = u8::try_from(value).unwrap_or(u8::MAX);
limits = limits.with_max_window_log(log).unwrap();
}
}
}
DecoderConfig::DEFAULT
.with_frame_mode(FrameMode::Single)
.with_limits(limits)
}