#![forbid(unsafe_code)]
use crate::core::candidate::BaseChunk;
use crate::core::extent::ChunkId;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
pub enum Channel {
PrevVersion = 0,
Adjacent = 1,
SharedContent = 2,
PrevInFile = 3,
FamilyBase = 4,
Universe = 5,
Rans = 6,
Raw = 7,
SharedDict = 8,
}
impl Channel {
pub const ALL: [Channel; 9] = [
Channel::PrevVersion,
Channel::Adjacent,
Channel::SharedContent,
Channel::PrevInFile,
Channel::FamilyBase,
Channel::Universe,
Channel::Rans,
Channel::Raw,
Channel::SharedDict,
];
pub const fn name(self) -> &'static str {
match self {
Channel::PrevVersion => "prev_version",
Channel::Adjacent => "adjacent",
Channel::SharedContent => "shared_content",
Channel::PrevInFile => "prev_in_file",
Channel::FamilyBase => "family_base",
Channel::Universe => "universe",
Channel::Rans => "rans",
Channel::Raw => "raw",
Channel::SharedDict => "shared_dict",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Features {
pub channel: Channel,
pub residual_ratio: f64,
pub diff_density: f64,
pub diff_runs: u32,
pub diff_positions: u32,
pub hist_change: f64,
pub exact_match: bool,
}
impl Features {
pub fn measurement(&self) -> f64 {
let x = self.residual_ratio.clamp(0.0, 1.0);
let v = 1.0 - (1.0 + x).log2() / 2.0;
v.clamp(0.0, 1.0)
}
pub fn from_base(channel: Channel, target: &[u8], base: Option<&BaseChunk>) -> Features {
match base {
None => Features {
channel,
residual_ratio: 1.0,
diff_density: 1.0,
diff_runs: 0,
diff_positions: 0,
hist_change: 1.0,
exact_match: false,
},
Some(b) => {
if b.bytes.len() != target.len() {
return Features {
channel,
residual_ratio: 1.0,
diff_density: 1.0,
diff_runs: 0,
diff_positions: 0,
hist_change: 1.0,
exact_match: false,
};
}
let (positions, runs) = crate::entropy::residual::diff_summary(target, &b.bytes);
let n = target.len() as f64;
let density = if n == 0.0 { 0.0 } else { positions as f64 / n };
let residual_ratio = density; let mut hist_change = 0.0;
if n > 0.0 {
let mut ht = [0i64; 256];
let mut hb = [0i64; 256];
for &x in target {
ht[x as usize] += 1;
}
for &x in &b.bytes {
hb[x as usize] += 1;
}
let mut l1 = 0i64;
for i in 0..256 {
l1 += (ht[i] - hb[i]).abs();
}
hist_change = (l1 as f64 / (2.0 * n)).clamp(0.0, 1.0);
}
Features {
channel,
residual_ratio,
diff_density: density,
diff_runs: runs as u32,
diff_positions: positions as u32,
hist_change,
exact_match: positions == 0,
}
}
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct ChunkKey {
pub ino: u64,
pub index: u64,
pub content_id: ChunkId,
}
impl ChunkKey {
pub const fn new(ino: u64, index: u64, content_id: ChunkId) -> Self {
Self {
ino,
index,
content_id,
}
}
}