#![forbid(unsafe_code)]
use crate::optimizer::policy::OptimizeOptions;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ForegroundMode {
Full,
Cheap,
RawOnly,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct ForegroundPolicy {
pub mode: ForegroundMode,
pub high_entropy_bits: f64,
pub probe_bytes: usize,
}
impl Default for ForegroundPolicy {
fn default() -> Self {
Self {
mode: ForegroundMode::Full,
high_entropy_bits: 7.2,
probe_bytes: 4096,
}
}
}
impl ForegroundPolicy {
pub const fn full() -> Self {
Self {
mode: ForegroundMode::Full,
high_entropy_bits: 7.2,
probe_bytes: 4096,
}
}
pub const fn cheap() -> Self {
Self {
mode: ForegroundMode::Cheap,
high_entropy_bits: 7.2,
probe_bytes: 4096,
}
}
pub const fn raw_only() -> Self {
Self {
mode: ForegroundMode::RawOnly,
high_entropy_bits: 7.2,
probe_bytes: 4096,
}
}
pub fn allow_full_search(&self, chunk: &[u8]) -> bool {
match self.mode {
ForegroundMode::Full => true,
ForegroundMode::RawOnly => false,
ForegroundMode::Cheap => !high_entropy(chunk, self),
}
}
pub fn family_evaluations_allowed(&self) -> bool {
self.mode != ForegroundMode::RawOnly
}
}
pub fn sampled_entropy(chunk: &[u8], probe_bytes: usize) -> f64 {
if chunk.is_empty() {
return 0.0;
}
let n = probe_bytes.min(chunk.len());
let base_step = (chunk.len() / n.max(1)).max(1);
let mut best = f64::INFINITY;
for shift in 0..3usize {
let step = base_step.saturating_add(shift).max(1);
let mut hist = [0u32; 256];
let mut counted = 0usize;
let mut i = 0usize;
while i < chunk.len() && counted < n {
hist[chunk[i] as usize] += 1;
counted += 1;
i += step;
}
if counted == 0 {
continue;
}
let mut entropy = 0.0f64;
for &c in &hist {
if c == 0 {
continue;
}
let p = c as f64 / counted as f64;
entropy -= p * p.log2();
}
best = best.min(entropy);
}
if best.is_infinite() { 0.0 } else { best }
}
pub fn high_entropy(chunk: &[u8], policy: &ForegroundPolicy) -> bool {
if chunk.len() < 256 {
return false;
}
sampled_entropy(chunk, policy.probe_bytes) >= policy.high_entropy_bits
}
pub fn is_degenerate(chunk: &[u8]) -> bool {
let Some(&first) = chunk.first() else {
return true;
};
chunk.iter().all(|&b| b == first)
}
pub fn foreground_allows(
options: &OptimizeOptions,
policy: &ForegroundPolicy,
chunk: &[u8],
) -> ForegroundFamilySet {
if !policy.allow_full_search(chunk) {
return ForegroundFamilySet {
dedup: true,
zero_fill: true,
configurational: false,
byte_rans: false,
sequence_rans: false,
sequence_deep: false,
sequence_dict: false,
shared_dict: false,
bases: false,
universe: false,
};
}
ForegroundFamilySet {
dedup: true,
zero_fill: true,
configurational: options.allow_configurational,
byte_rans: options.allow_byte_rans,
sequence_rans: options.allow_sequence_rans,
sequence_deep: options.allow_sequence_rans_deep,
sequence_dict: options.allow_sequence_dict,
shared_dict: options.allow_shared_dict,
bases: options.allow_bases,
universe: options.allow_universe,
}
}
#[derive(Debug, Clone, Copy)]
pub struct ForegroundFamilySet {
pub dedup: bool,
pub zero_fill: bool,
pub configurational: bool,
pub byte_rans: bool,
pub sequence_rans: bool,
pub sequence_deep: bool,
pub sequence_dict: bool,
pub shared_dict: bool,
pub bases: bool,
pub universe: bool,
}
impl ForegroundFamilySet {
pub fn unrestricted() -> Self {
Self {
dedup: true,
zero_fill: true,
configurational: true,
byte_rans: true,
sequence_rans: true,
sequence_deep: true,
sequence_dict: true,
shared_dict: true,
bases: true,
universe: true,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn entropy_classification_is_deterministic_and_sane() {
let zeros = vec![0u8; 65536];
let mut state = 0x9e37_79b9_7f4a_7c15u64;
let random: Vec<u8> = (0..65536u32)
.map(|_| {
state = state
.wrapping_mul(6364136223846793005)
.wrapping_add(1442695040888963407);
(state >> 33) as u8
})
.collect();
let periodic: Vec<u8> = (0..65536u32)
.map(|i| (i.wrapping_mul(2654435761)) as u8)
.collect();
let text: Vec<u8> = (0..65536u32).map(|i| b'a' + (i % 26) as u8).collect();
let p = ForegroundPolicy::cheap();
let e0 = sampled_entropy(&zeros, 4096);
let er = sampled_entropy(&random, 4096);
let ep = sampled_entropy(&periodic, 4096);
let et = sampled_entropy(&text, 4096);
assert_eq!(e0, 0.0, "zeros are zero-entropy");
assert!(er >= 7.9, "true random is near 8 bits/byte (got {er})");
assert!(ep < 6.0, "periodic data must not look random (got {ep})");
assert!(et < 5.0, "text is low-entropy (got {et})");
assert!(high_entropy(&random, &p));
assert!(!high_entropy(&text, &p));
assert!(!high_entropy(&zeros, &p));
assert!(
!high_entropy(&periodic, &p),
"periodic data stays in the full search"
);
assert_eq!(sampled_entropy(&random, 4096), er);
}
#[test]
fn tiny_chunks_never_skip() {
let p = ForegroundPolicy::cheap();
assert!(!high_entropy(&[7u8; 100], &p));
assert!(p.allow_full_search(&[7u8; 100]));
}
}