lbzip2/lib.rs
1//! lbzip2-rs — Pure Rust parallel bzip2 decompressor.
2//!
3//! Architecture:
4//! 1 reader thread fills a ChunkRevolver ring buffer (~100 MB slots)
5//! with raw compressed bzip2 data.
6//!
7//! Per slot the reader does a cheap SIMD bit-scan to locate bzip2 block
8//! boundaries (magic 0x314159265359 at arbitrary bit offsets), then
9//! dispatches N sub-ranges to a worker pool.
10//!
11//! Each worker independently decodes its Burrows-Wheeler blocks and
12//! produces decompressed output. Results are reassembled in order and
13//! emitted as a streaming `Read`.
14
15pub mod bitreader;
16pub mod block;
17pub mod block_scan;
18pub mod bwt;
19pub mod chunk;
20pub mod huffman;
21pub mod mtf;
22pub mod parallel;
23pub mod reader;
24pub mod stream;
25
26/// bzip2 block magic: π digits — 0x314159265359 (48 bits, bit-aligned).
27pub const BLOCK_MAGIC: u64 = 0x314159265359;
28
29/// bzip2 end-of-stream magic: √π digits — 0x177245385090 (48 bits).
30pub const FINAL_MAGIC: u64 = 0x177245385090;
31
32// ── Dedicated thread pool ────────────────────────────────────────────────────
33
34use std::sync::OnceLock;
35
36static POOL: OnceLock<rayon::ThreadPool> = OnceLock::new();
37
38/// Get (or create) lbzip2's dedicated rayon thread pool.
39///
40/// Sized to the number of physical cores — separate from the caller's
41/// global rayon pool so bzip2 decode doesn't compete with VTD parse,
42/// PBF encode, etc.
43///
44/// Override with `LBZIP2_THREADS` env var.
45pub fn thread_pool() -> &'static rayon::ThreadPool {
46 POOL.get_or_init(|| {
47 let n = std::env::var("LBZIP2_THREADS")
48 .ok()
49 .and_then(|v| v.parse().ok())
50 .unwrap_or_else(|| {
51 std::thread::available_parallelism()
52 .map(|n| n.get())
53 .unwrap_or(4)
54 });
55 rayon::ThreadPoolBuilder::new()
56 .num_threads(n)
57 .thread_name(|i| format!("lbzip2-{i}"))
58 .build()
59 .expect("failed to create lbzip2 thread pool")
60 })
61}