pub mod bwt;
pub mod mtf;
pub mod rle;
use crate::alloc::vec::Vec;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Transform {
Rle,
Bwt,
BwtSafe, Mtf,
Delta,
PredictiveDelta,
Yuv,
ChannelSeparation(usize),
BlockDelta(usize),
XorDelta(usize),
MultiByteXor(usize),
Auto, }
pub struct TransformChain {
chain: Vec<Transform>,
}
impl TransformChain {
pub fn new(chain: Vec<Transform>) -> Self {
Self { chain }
}
pub fn apply(&self, mut data: Vec<u8>) -> (Vec<u8>, Vec<usize>) {
let mut bwt_indices = Vec::new();
for t in &self.chain {
let start_len = data.len();
match t {
Transform::Rle => data = rle::rle_encode(&data),
Transform::Bwt => {
let (b, idx) = bwt::bwt_transform(&data);
data = b;
bwt_indices.push(idx);
}
Transform::BwtSafe => {
let (b, _) = bwt::bwt_encode_safe(&data);
data = b;
}
Transform::Mtf => data = mtf::mtf_transform(&data),
Transform::Delta => data = crate::poor_compress::DeltaTransform::encode(&data),
Transform::PredictiveDelta => {
data = crate::poor_compress::PredictiveDelta::encode(&data)
}
Transform::Yuv => {
data = crate::poor_compress::ChannelSeparator::new(3).separate_yuv(&data)
}
Transform::ChannelSeparation(channels) => {
data = crate::poor_compress::ChannelSeparator::new(*channels).separate(&data)
}
Transform::BlockDelta(size) => {
data = crate::poor_compress::BlockDeltaTransform::new(*size).encode(&data)
}
Transform::XorDelta(size) => {
data = crate::poor_compress::XorDeltaTransform::new(*size).encode(&data)
}
Transform::MultiByteXor(width) => {
data = crate::poor_compress::MultiByteXor::new(*width).encode(&data)
}
Transform::Auto => {
#[cfg(feature = "std")]
std::println!("[Auto Apply] Start: {} bytes", data.len());
let (b, indices) = bwt::bwt_transform_blocked(&data);
data = b;
bwt_indices.extend(indices);
#[cfg(feature = "std")]
std::println!("[Auto Apply] After BWT: {} bytes", data.len());
data = mtf::mtf_transform(&data);
#[cfg(feature = "std")]
std::println!("[Auto Apply] After MTF: {} bytes", data.len());
data = crate::poor_compress::DeltaTransform::encode(&data);
#[cfg(feature = "std")]
std::println!("[Auto Apply] After Delta: {} bytes", data.len());
data = rle::rle_encode(&data);
#[cfg(feature = "std")]
std::println!("[Auto Apply] After RLE: {} bytes", data.len());
}
}
#[cfg(feature = "std")]
if start_len > 0 {
std::println!(
"[Transform {:?}] {} -> {} (Step Ratio: {:.4})",
t,
start_len,
data.len(),
data.len() as f64 / start_len as f64
);
}
}
(data, bwt_indices)
}
pub fn inverse(&self, mut data: Vec<u8>, mut bwt_indices: Vec<usize>) -> Vec<u8> {
for t in self.chain.iter().rev() {
match t {
Transform::Rle => data = rle::rle_decode(&data),
Transform::Bwt => {
let idx = bwt_indices.pop().expect("Missing BWT index");
data = bwt::bwt_inverse(&data, idx);
}
Transform::BwtSafe => {
data = bwt::bwt_decode_safe(&data, 0);
}
Transform::Mtf => data = mtf::mtf_inverse(&data),
Transform::Delta => data = crate::poor_compress::DeltaTransform::decode(&data),
Transform::PredictiveDelta => {
data = crate::poor_compress::PredictiveDelta::decode(&data)
}
Transform::Yuv => {
data = crate::poor_compress::ChannelSeparator::new(3).interleave_yuv(&data)
}
Transform::ChannelSeparation(channels) => {
data = crate::poor_compress::ChannelSeparator::new(*channels).interleave(&data)
}
Transform::BlockDelta(size) => {
data = crate::poor_compress::BlockDeltaTransform::new(*size).decode(&data)
}
Transform::XorDelta(size) => {
data = crate::poor_compress::XorDeltaTransform::new(*size).decode(&data)
}
Transform::MultiByteXor(width) => {
data = crate::poor_compress::MultiByteXor::new(*width).decode(&data)
}
Transform::Auto => {
#[cfg(feature = "std")]
std::println!("[Auto Inverse] Start: {} bytes", data.len());
data = rle::rle_decode(&data);
#[cfg(feature = "std")]
std::println!("[Auto Inverse] After RLE: {} bytes", data.len());
data = crate::poor_compress::DeltaTransform::decode(&data);
#[cfg(feature = "std")]
std::println!("[Auto Inverse] After Delta: {} bytes", data.len());
data = mtf::mtf_inverse(&data);
#[cfg(feature = "std")]
std::println!("[Auto Inverse] After MTF: {} bytes", data.len());
let block_size = bwt::BWT_BLOCK_SIZE;
let n_blocks = if data.is_empty() {
0
} else {
(data.len() + block_size - 1) / block_size
};
let start_idx = bwt_indices.len().saturating_sub(n_blocks);
let valid_indices: Vec<usize> = bwt_indices.drain(start_idx..).collect();
if valid_indices.len() != n_blocks {
#[cfg(feature = "std")]
std::println!(
"[Transform::Auto] Warning: Index count mismatch. Expected {}, got {}",
n_blocks,
valid_indices.len()
);
}
data = bwt::bwt_inverse_blocked(&data, &valid_indices);
#[cfg(feature = "std")]
std::println!("[Auto Inverse] After BWT: {} bytes", data.len());
}
}
}
data
}
}