1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
//! PPMd variant H (7-Zip's "Ppmd7") compression and decompression.
//!
//! `ppmd-turbo` implements Dmitry Shkarin's PPMd variant H context model, its
//! sub-allocator and secondary escape estimation, and the two range coders
//! that carry it in the wild:
//!
//! - the LZMA-style range coder 7-Zip uses for the `PPMD` method in `.7z`
//! ([`SevenZDecoder`], [`SevenZEncoder`]), and
//! - the carry-less range coder RAR 2.9 through 4.x uses for its PPMd blocks
//! ([`RarPpmd`]; RAR5 has no PPMd).
//!
//! Output is bit-exact with 7-Zip and RARLAB unrar: a 7z stream encoded here
//! is byte-identical to 7-Zip's for the same parameters, and a RAR stream
//! decodes to exactly what unrar produces. Writing RAR blocks or archives is
//! out of scope by design; [`CarrylessEncoder`] and [`CarrylessDecoder`]
//! handle raw carry-less streams for round-trip testing only.
//!
//! # The step API
//!
//! Every codec is a step machine over slices the caller owns: a call takes
//! input and an output slice and reports a [`Progress`] with exact
//! `consumed` and `produced` counts and a status. The codecs never keep
//! caller bytes between calls; a non-final call decodes only while a whole
//! symbol's worth of input ([`Params::max_input_per_symbol`], at most
//! [`MAX_INPUT_PER_SYMBOL`]) remains. Model memory is an [`Arena`] the
//! caller can reuse across streams. Errors are typed ([`ErrorKind`]),
//! `Copy`, carry the stream [`Position`], and are sticky until a reset. The
//! [`io`] module wraps the 7z pair in `Read` and `Write`.
//!
//! ```
//! use ppmd_turbo::{Params, SevenZDecoder, SevenZEncoder, SevenZStatus};
//!
//! let data = b"the quick brown fox jumps over the lazy dog";
//! let params = Params::new(6, 1 << 20)?.reduced_for(data.len() as u64);
//!
//! let mut encoder = SevenZEncoder::new(params)?;
//! let mut stream = vec![0u8; 128];
//! let mut len = encoder.encode(data, &mut stream)?.produced;
//! while !{
//! let fin = encoder.finish(&mut stream[len..], false)?;
//! len += fin.produced;
//! fin.done
//! } {}
//!
//! let mut decoder = SevenZDecoder::new(params, Some(data.len() as u64))?;
//! let mut out = vec![0u8; data.len()];
//! let step = decoder.decode(&stream[..len], true, &mut out)?;
//! assert_eq!(step.status, SevenZStatus::ReachedSize);
//! assert_eq!(step.consumed, len);
//! assert_eq!(&out[..], data);
//! # Ok::<(), ppmd_turbo::Error>(())
//! ```
//!
//! # Features
//!
//! - `std` (default): the [`io`] adapters, the `io::Error` conversion and
//! run-time x86 SIMD detection. Without it the crate builds on `core` and
//! `alloc`, choosing SIMD tiers at compile time; this is checked, not
//! promised. [`Error`] implements `core::error::Error` either way.
//! - `internals`: the engine, for the crate's own fuzz targets, benches and
//! differential tests. Hidden and unstable.
//!
//! `unsafe` is permitted where it pays for itself, and only with a
//! `// SAFETY:` proof on every block, Miri coverage where Miri can run, and a
//! fuzz target over every decoder and encoder entry point.
extern crate alloc as alloc_crate;
extern crate core as std;
pub
pub
pub
pub
pub use Arena;
pub use ;
pub use ;
pub use ;
pub use ;
pub use ;
pub const PPMD7_MIN_ORDER: u32 = MIN_ORDER;
pub const PPMD7_MAX_ORDER: u32 = MAX_ORDER;
pub const PPMD7_MIN_MEM_SIZE: u32 = MIN_MEM;
pub const PPMD7_MAX_MEM_SIZE: u32 = MAX_MEM;
/// The symbol value of the end marker in the model's encoder
/// (`PPMD7_SYM_END` in 7-Zip).
pub const SYM_END: i32 = -1;
/// The model's decoder result for a count past the frequency total, which a
/// valid stream never produces (`PPMD7_SYM_ERROR` in 7-Zip).
pub const SYM_ERROR: i32 = -2;
/// Every codec moves between threads; none is shared (`Sync`), because the
/// sub-allocator's free lists use `Cell`.
const _: = ;