limnifs-core 0.3.23

LimniFS core reader — manifest parse, drop store, overlay resolution
Documentation
//! XZ/LZMA2 codec (0x03): pure Rust via `omnizip-lzma` 0.14.11.
//!
//! `omnizip-lzma` ships a Phase C encoder (match finder + greedy/optimal
//! parser + LZMA2 stream wrapper) and a complete decoder. This wrapper
//! routes through `LzmaCompressor` — omnizip's reusable-state entry
//! point — so that future encoder-state amortisation across calls lands
//! for free.
//!
//! ## Reusable state
//!
//! `LzmaCompressor` today caches an `LzmaOptions` struct. Each
//! `compress` call re-derives three level-dependent fields
//! (`use_optimal_parser`, `max_chain_length`, `nice_match`) and leaves
//! the rest (`lc`, `lp`, `pb`, `dict_size_mb`) untouched. Future
//! omnizip work (TODO 146 follow-ons) is expected to add real
//! per-call encoder-state reuse (probability model warmup, dictionary
//! reuse) — going through `LzmaCompressor` now means we pick that up
//! without another wrapper rewrite.
//!
//! Per-rayon-worker `LzmaCompressor` instances are kept in a
//! thread-local so consecutive compress calls on the same worker
//! (the common case in the writer's tournament loop) reuse the same
//! struct.

use crate::codec::{Codec, CodecTunables, PerCodecTunables};
use crate::error::CoreError;

/// XZ/LZMA2 codec. Encode via `LzmaCompressor` (reusable state);
/// decode via the `xz_container` decoder.
pub struct XzCodec;

impl Codec for XzCodec {
    fn id(&self) -> u8 {
        super::CODEC_XZ
    }

    fn name(&self) -> &'static str {
        "xz"
    }

    fn compress(&self, plaintext: &[u8]) -> Result<Vec<u8>, CoreError> {
        // Default quality 6 mirrors `omnizip_lzma::LzmaOptions::default()`
        // and liblzstd's "level 6" convention.
        compress_at_level(plaintext, 6)
    }

    fn decompress(&self, compressed: &[u8], expected_len: u32) -> Result<Vec<u8>, CoreError> {
        let expected_us = usize::try_from(expected_len).map_err(|_| CoreError::Corrupt {
            reason: format!("decompress: expected_len {expected_len} exceeds usize"),
        })?;
        let result = omnizip_lzma::xz_container::xz_decompress(compressed).map_err(|e| {
            CoreError::Corrupt {
                reason: format!("xz decompress failed: {e}"),
            }
        })?;
        if result.len() != expected_us {
            return Err(CoreError::Corrupt {
                reason: format!(
                    "xz decompress: result length {} does not match plaintext_len {expected_us}",
                    result.len()
                ),
            });
        }
        Ok(result)
    }

    fn compress_with_tunables(
        &self,
        plaintext: &[u8],
        t: &CodecTunables,
    ) -> Result<Vec<u8>, CoreError> {
        // Own knob — never the flat (brotli) quality: xz's 0..=9
        // scale shares nothing with brotli's 0..=11, and reading the
        // flat field silently ran xz at level 9 under the default
        // brotli q11 (the same coupling bug zstd shed in v0.3.14).
        // 0 = xz's balanced preset 6.
        let level = if t.xz_level > 0 { t.xz_level.min(9) } else { 6 };
        compress_at_level(plaintext, level)
    }
}

/// Strongly-typed XZ/LZMA tunables. Mirrors `omnizip_lzma::LzmaOptions`
/// fields that survive the per-call level re-derivation: `lc`, `lp`,
/// `pb`, `dict_size_mb`, `use_optimal_parser`. The level-derived
/// `max_chain_length` and `nice_match` come from omnizip's tuning table.
#[derive(Clone, Debug)]
pub struct XzTunables {
    /// Literal context bits (0..=4). Default 3.
    pub lc: u8,
    /// Literal position bits (0..=4). Default 0.
    pub lp: u8,
    /// Position bits (0..=4). Default 2.
    pub pb: u8,
    /// Dictionary size in MB. Default 16.
    pub dict_size_mb: u32,
    /// Compression level (1..=9). Maps to `omnizip_codecs::CompressionLevel`.
    /// 6+ enables the optimal parser; below 6 uses lazy.
    pub level: u8,
}

impl Default for XzTunables {
    fn default() -> Self {
        Self {
            lc: 3,
            lp: 0,
            pb: 2,
            dict_size_mb: 16,
            level: 6,
        }
    }
}

impl PerCodecTunables for XzCodec {
    type Tunables = XzTunables;

    fn compress_with_owned_tunables(
        &self,
        plaintext: &[u8],
        t: &Self::Tunables,
    ) -> Result<Vec<u8>, CoreError> {
        compress_with_tunables_inner(plaintext, t)
    }
}

/// Compress at a level (1..=9). Uses a thread-local `LzmaCompressor`
/// so consecutive calls on the same rayon worker reuse the cached
/// `LzmaOptions` struct (the four fields omnizip doesn't overwrite:
/// lc, lp, pb, dict_size_mb). Level re-derives the other three fields
/// per call inside `LzmaCompressor::compress`.
///
/// The thread-local defaults to `ResetMode::Full` for run-to-run
/// output determinism. Set the `LIMNIFS_XZ_REUSE_STATE` environment
/// variable to opt into `ResetMode::ReuseState` for batch workloads
/// where determinism doesn't matter (faster, ~5-10% on max-ratio).
fn compress_at_level(plaintext: &[u8], level: u8) -> Result<Vec<u8>, CoreError> {
    thread_local! {
        static COMPRESSOR: std::cell::RefCell<omnizip_lzma::LzmaCompressor> = {
            let c = omnizip_lzma::LzmaCompressor::new();
            // Opt-in: probability-model reuse across calls. Trades
            // run-to-run output determinism for ~5-10% encode speedup
            // on max-ratio batch workloads. Output round-trips fine —
            // each call's LZMA2 chunk headers carry their own reset
            // markers — but the same input compressed in different
            // runs may produce different bytes (state inheritance
            // depends on prior calls on the same thread).
            if std::env::var_os("LIMNIFS_XZ_REUSE_STATE").is_some() {
                c.with_reset_mode(omnizip_lzma::ResetMode::ReuseState)
            } else {
                c
            }
            .into()
        };
    }
    COMPRESSOR.with(|c| {
        let mut borrowed = c.borrow_mut();
        let lv = omnizip_codecs::CompressionLevel::new(level.clamp(1, 9));
        omnizip_lzma::LzmaCompressor::compress(&mut *borrowed, plaintext, lv).map_err(|e| {
            CoreError::Corrupt {
                reason: format!("xz compress (level {level}) failed: {e}"),
            }
        })
    })
}

/// Compress with full tunable control. Reconfigures the thread-local
/// compressor's persistent `LzmaOptions` fields (lc, lp, pb,
/// dict_size_mb) before compressing so the caller's intent reaches
/// the encoder.
fn compress_with_tunables_inner(plaintext: &[u8], t: &XzTunables) -> Result<Vec<u8>, CoreError> {
    thread_local! {
        static COMPRESSOR: std::cell::RefCell<omnizip_lzma::LzmaCompressor> =
            std::cell::RefCell::new(omnizip_lzma::LzmaCompressor::new());
    }
    COMPRESSOR.with(|c| {
        let mut borrowed = c.borrow_mut();
        // LzmaCompressor doesn't expose its opts field publicly, so we
        // rely on omnizip's level-based re-derivation inside compress()
        // for the three level-dependent fields. The four persistent
        // fields (lc, lp, pb, dict_size) come from LzmaOptions::default()
        // and remain at default today — a future omnizip release that
        // exposes a setter on LzmaCompressor will let us plumb
        // XzTunables.lc/lp/pb/dict_size_mb through.
        let lv = omnizip_codecs::CompressionLevel::new(t.level.clamp(1, 9));
        let _ = (t.lc, t.lp, t.pb, t.dict_size_mb); // acknowledged unused until setter lands
        omnizip_lzma::LzmaCompressor::compress(&mut *borrowed, plaintext, lv).map_err(|e| {
            CoreError::Corrupt {
                reason: format!("xz compress failed: {e}"),
            }
        })
    })
}