oxideav_opus/range_encoder.rs
1//! Range encoder primitives for the Opus codec.
2//!
3//! This module implements the bit-exact range *encoder* described in
4//! RFC 6716 §5.1 (`docs/audio/opus/rfc6716-opus.txt`). It is the exact
5//! counterpart of the [`crate::range_decoder`] module: any sequence of
6//! symbols written here decodes back to the identical sequence through
7//! [`crate::range_decoder::RangeDecoder`], and — per §5.1 — the encoder
8//! `rng` after a symbol matches the decoder `rng` after decoding the
9//! same symbol. The implementation is clean-room: every routine is
10//! transcribed from the prose and equations in RFC 6716 §5.1; no
11//! external library source was consulted.
12//!
13//! The range encoder is the SHARED entropy primitive that both the SILK
14//! and CELT layers of an Opus encoder invoke for every coded symbol.
15//!
16//! The following routines are wired up:
17//!
18//! * Initialization (§5.1).
19//! * [`RangeEncoder::encode`] — the generic `ec_encode(fl, fh, ft)`
20//! symbol-update path (§5.1.1), with renormalization (§5.1.1.1) and
21//! carry propagation / output buffering (§5.1.1.2).
22//! * [`RangeEncoder::encode_bin`] for power-of-two `ft = 1<<ftb`
23//! (§5.1.2.1, `ec_encode_bin`).
24//! * [`RangeEncoder::enc_bit_logp`] for a single binary symbol with
25//! probability `2**-logp` of a "1" (§5.1.2.2).
26//! * [`RangeEncoder::enc_icdf`] for inverse-CDF table encoding, sharing
27//! the decoder's `icdf[]` tables verbatim (§5.1.2.3).
28//! * [`RangeEncoder::enc_bits`] for raw bits packed at the end of the
29//! buffer (§5.1.3).
30//! * [`RangeEncoder::enc_uint`] for uniformly-distributed integers
31//! (§5.1.4).
32//! * [`RangeEncoder::tell`] / [`RangeEncoder::tell_frac`] for
33//! whole-bit / 1/8th-bit accounting (§5.1.6), matching the decoder's
34//! [`crate::range_decoder::RangeDecoder::tell`] value bit-for-bit
35//! after the same symbols.
36//! * [`RangeEncoder::finish`] — stream finalization (§5.1.5,
37//! `ec_enc_done`), which selects the terminating code value and lays
38//! out the range bytes and the trailing raw-bit region.
39
40/// Bit-exact CELT/SILK range encoder state per RFC 6716 §5.1.
41///
42/// The state four-tuple `(val, rng, rem, ext)` from §5.1 is carried
43/// directly: `val` is the low end of the current range, `rng` its size,
44/// `rem` a single buffered non-propagating output byte (or `-1` for
45/// "none yet"), and `ext` a count of pending carry-propagating (`255`)
46/// output bytes. Range-coder bytes accumulate front-to-back in `buf`;
47/// raw bits (§5.1.3) accumulate back-to-front in `end_bytes` /
48/// `end_window` and are appended as the buffer tail at [`Self::finish`].
49#[derive(Debug, Clone)]
50pub struct RangeEncoder {
51 /// Range-coder output bytes, in forward order (index 0 first).
52 buf: Vec<u8>,
53 /// Range size; the renormalization invariant is `rng > 2**23`.
54 rng: u32,
55 /// Low end of the current range (masked to 31 bits at rest).
56 val: u32,
57 /// Buffered non-propagating output byte, `0..=254`, or `-1` for
58 /// "no byte buffered yet" (§5.1.1.2).
59 rem: i32,
60 /// Count of pending carry-propagating (`255`) output bytes
61 /// (§5.1.1.2).
62 ext: u32,
63 /// Partial raw-bit window: the next bit to emit sits in bit 0
64 /// (§5.1.3). Holds fewer than 8 bits at rest.
65 end_window: u32,
66 /// Number of valid bits currently in `end_window` (0..=7 at rest).
67 nend_bits: u32,
68 /// Completed raw-bit bytes. `end_bytes[0]` is the LAST byte of the
69 /// finished stream, `end_bytes[1]` the second-to-last, and so on —
70 /// matching the decoder's back-to-front raw-bit reader (§4.1.4).
71 end_bytes: Vec<u8>,
72 /// Running tally of whole bits the range coder has produced
73 /// (RFC 6716 §5.1.6 / §4.1.6 `nbits_total`).
74 nbits_total: u32,
75 /// Number of raw bits emitted so far, added into the bit-usage
76 /// accounting on top of `nbits_total` (§4.1.6).
77 nbits_raw: u32,
78}
79
80impl Default for RangeEncoder {
81 fn default() -> Self {
82 Self::new()
83 }
84}
85
86impl RangeEncoder {
87 /// Renormalization threshold from §5.1.1.1: normalize until
88 /// `rng > 2**23`.
89 const RNG_MIN: u32 = 1 << 23;
90
91 /// Depth of the decoder's forward-read lookahead, in bytes. The
92 /// 31-bit range window (`val < 2**31`) plus the §4.1.1 initialization
93 /// pre-read means the decoder can consume up to one full range window
94 /// (4 bytes) beyond the last committed range byte. Used at
95 /// [`Self::finish`] to size the zero pad that isolates the raw-bit
96 /// tail from the range reader.
97 const RANGE_LOOKAHEAD_BYTES: usize = 4;
98
99 /// Initialize the range encoder per RFC 6716 §5.1.
100 ///
101 /// The state vector is `(val, rng, rem, ext) = (0, 2**31, -1, 0)`.
102 /// `nbits_total` starts at 33 so that [`Self::tell`] reports the
103 /// same value as a freshly-initialized decoder (which reaches
104 /// `nbits_total == 33`, `rng == 2**31`, `tell() == 1` after its
105 /// §4.1.1 initialization normalize).
106 pub fn new() -> Self {
107 Self {
108 buf: Vec::new(),
109 rng: 1 << 31,
110 val: 0,
111 rem: -1,
112 ext: 0,
113 end_window: 0,
114 nend_bits: 0,
115 end_bytes: Vec::new(),
116 // §4.1.6/§5.1.6: matches the decoder's post-init value so
117 // `tell()` agrees symbol-for-symbol.
118 nbits_total: 33,
119 nbits_raw: 0,
120 }
121 }
122
123 /// Whole-bit budget produced so far, per RFC 6716 §5.1.6 / §4.1.6.1.
124 ///
125 /// Equal to `nbits_total - ilog(rng) + nbits_raw`; matches the
126 /// decoder's `tell()` after the same symbols.
127 pub fn tell(&self) -> u32 {
128 let lg = 32 - self.rng.leading_zeros();
129 self.nbits_total
130 .saturating_sub(lg)
131 .saturating_add(self.nbits_raw)
132 }
133
134 /// 1/8th-bit-precision budget produced so far, per RFC 6716 §5.1.6 /
135 /// §4.1.6.2. Matches the decoder's `tell_frac()` after the same
136 /// symbols.
137 pub fn tell_frac(&self) -> u32 {
138 let lg0 = 32 - self.rng.leading_zeros();
139 let mut r_q15 = self.rng >> (lg0 - 16);
140 let mut lg_frac = lg0;
141 for _ in 0..3 {
142 r_q15 = (r_q15 * r_q15) >> 15;
143 let bit = r_q15 >> 16;
144 lg_frac = 2 * lg_frac + bit;
145 if bit == 1 {
146 r_q15 >>= 1;
147 }
148 }
149 self.nbits_total
150 .saturating_mul(8)
151 .saturating_sub(lg_frac)
152 .saturating_add(self.nbits_raw.saturating_mul(8))
153 }
154
155 /// Encode symbol `k` described by the three-tuple `(fl, fh, ft)`,
156 /// per RFC 6716 §5.1.1 (`ec_encode`).
157 ///
158 /// Requires `0 <= fl < fh <= ft` and `1 <= ft <= 2**16`. The §5.1.1
159 /// update narrows the range to the symbol's `[fl, fh)` sub-interval
160 /// of `[0, ft)`. The `fl == 0` branch subtracts `(rng/ft)*(ft - fh)`
161 /// from `rng` so the top symbol absorbs the integer-division
162 /// remainder — the exact mirror of the decoder's §4.1.2 update, which
163 /// is what keeps encoder `rng` equal to decoder `rng`.
164 pub fn encode(&mut self, fl: u32, fh: u32, ft: u32) {
165 debug_assert!(fl < fh && fh <= ft && ft >= 1);
166 let r = self.rng / ft;
167 if fl > 0 {
168 self.val = self.val.wrapping_add(self.rng - r.wrapping_mul(ft - fl));
169 self.rng = r.wrapping_mul(fh - fl);
170 } else {
171 self.rng -= r.wrapping_mul(ft - fh);
172 }
173 self.normalize();
174 }
175
176 /// Encode symbol `k` for a power-of-two total `ft = 1<<ftb`, per
177 /// RFC 6716 §5.1.2.1 (`ec_encode_bin`). Division-free equivalent of
178 /// [`Self::encode`] with `ft = 1<<ftb`.
179 pub fn encode_bin(&mut self, fl: u32, fh: u32, ftb: u32) {
180 let ft = 1u32 << ftb;
181 debug_assert!(fl < fh && fh <= ft);
182 let r = self.rng >> ftb;
183 if fl > 0 {
184 self.val = self.val.wrapping_add(self.rng - r.wrapping_mul(ft - fl));
185 self.rng = r.wrapping_mul(fh - fl);
186 } else {
187 self.rng -= r.wrapping_mul(ft - fh);
188 }
189 self.normalize();
190 }
191
192 /// Encode a single binary symbol whose "1" has probability
193 /// `2**-logp`, per RFC 6716 §5.1.2.2 (`ec_enc_bit_logp`).
194 ///
195 /// Equivalent to `ec_encode` with `(fl, fh, ft)` equal to
196 /// `(0, (1<<logp)-1, 1<<logp)` for a `0` and
197 /// `((1<<logp)-1, 1<<logp, 1<<logp)` for a `1`. Multiplication- and
198 /// division-free.
199 pub fn enc_bit_logp(&mut self, bit: bool, logp: u32) {
200 let r = self.rng >> logp;
201 if bit {
202 // fl = (1<<logp)-1, fh = ft = 1<<logp; fh-fl = 1, ft-fl = 1.
203 self.val = self.val.wrapping_add(self.rng - r);
204 self.rng = r;
205 } else {
206 // fl = 0, fh = (1<<logp)-1, ft = 1<<logp; ft-fh = 1.
207 self.rng -= r;
208 }
209 self.normalize();
210 }
211
212 /// Encode symbol index `k` against an inverse-CDF table, per
213 /// RFC 6716 §5.1.2.3 (`ec_enc_icdf`). Uses the SAME `icdf[]` tables
214 /// as the decoder's [`crate::range_decoder::RangeDecoder::dec_icdf`]:
215 /// `icdf[j]` stores `(1<<ftb) - fh[j]`, terminated by a `0` entry.
216 ///
217 /// Per §5.1.2.3, `fl[k] = (1<<ftb) - icdf[k-1]` (or `0` if `k == 0`),
218 /// `fh[k] = (1<<ftb) - icdf[k]`, `ft = 1<<ftb`. The symbol update
219 /// then depends only on the `icdf[]` differences, so no total is
220 /// needed.
221 pub fn enc_icdf(&mut self, k: usize, icdf: &[u8], ftb: u32) {
222 // A zero-width symbol (fh == fl: a zero-probability PDF cell)
223 // would collapse `rng` to zero and make the stream undecodable;
224 // callers must never encode one.
225 debug_assert!(
226 if k == 0 {
227 (icdf[0] as u32) < (1u32 << ftb)
228 } else {
229 icdf[k - 1] > icdf[k]
230 },
231 "zero-probability icdf cell {k}"
232 );
233 let r = self.rng >> ftb;
234 if k > 0 {
235 let hi = icdf[k - 1] as u32;
236 let lo = icdf[k] as u32;
237 // ft - fl = icdf[k-1]; fh - fl = icdf[k-1] - icdf[k].
238 self.val = self.val.wrapping_add(self.rng - r.wrapping_mul(hi));
239 self.rng = r.wrapping_mul(hi - lo);
240 } else {
241 // fl = 0; ft - fh = icdf[0].
242 self.rng -= r.wrapping_mul(icdf[0] as u32);
243 }
244 self.normalize();
245 }
246
247 /// Encode `bits` raw bits (low bits of `value`), per RFC 6716
248 /// §5.1.3 (`ec_enc_bits`). Raw bits are packed at the END of the
249 /// output buffer, LSB-first, mirroring the decoder's back-to-front
250 /// reader. The first bit emitted here is the one the decoder reads
251 /// first.
252 pub fn enc_bits(&mut self, value: u32, bits: u32) {
253 debug_assert!(bits <= 32);
254 if bits == 0 {
255 return;
256 }
257 let mask: u64 = if bits >= 32 {
258 0xFFFF_FFFF
259 } else {
260 (1u64 << bits) - 1
261 };
262 let mut window = (self.end_window as u64) | ((value as u64 & mask) << self.nend_bits);
263 let mut n = self.nend_bits + bits;
264 while n >= 8 {
265 self.end_bytes.push((window & 0xFF) as u8);
266 window >>= 8;
267 n -= 8;
268 }
269 self.end_window = window as u32;
270 self.nend_bits = n;
271 self.nbits_raw += bits;
272 }
273
274 /// Encode one of `ft` equiprobable values `t` in `0..ft`, per
275 /// RFC 6716 §5.1.4 (`ec_enc_uint`). `ft` may be as large as
276 /// `2**32 - 1`. Values `ft <= 1` degenerate to a no-op (matching the
277 /// decoder returning the constant `0`).
278 pub fn enc_uint(&mut self, t: u32, ft: u32) {
279 debug_assert!(ft >= 1 && t < ft.max(1));
280 if ft <= 1 {
281 return;
282 }
283 // ftb = ilog(ft - 1): bits needed to store ft-1.
284 let ftb = 32 - (ft - 1).leading_zeros();
285 if ftb <= 8 {
286 self.encode(t, t + 1, ft);
287 } else {
288 let split = ftb - 8;
289 let hi = t >> split;
290 let top = ((ft - 1) >> split) + 1;
291 self.encode(hi, hi + 1, top);
292 self.enc_bits(t & ((1u32 << split) - 1), split);
293 }
294 }
295
296 /// Finalize the stream (§5.1.5, `ec_enc_done`) and return the packed
297 /// output bytes.
298 ///
299 /// Chooses the terminating code value `end` inside `[val, val + rng)`
300 /// with the most trailing zero bits `b` such that
301 /// `end + (1<<b) - 1` is still in the interval, flushes it through
302 /// the carry buffer, then appends the raw-bit region (§5.1.3) as a
303 /// disjoint tail, separated from the range data by a zero pad so the
304 /// decoder's forward range reader can zero-extend past the committed
305 /// bytes without consuming a raw byte.
306 pub fn finish(mut self) -> Vec<u8> {
307 let val = self.val;
308 let rng = self.rng;
309 // Default b = 0: end = val is always in the interval.
310 let mut end = val;
311 // Pick the largest b in 1..=31 whose rounded-up multiple of 2**b
312 // keeps `end + (2**b - 1)` inside `[val, val + rng)`.
313 for b in (1..=31u32).rev() {
314 let m = (1u64 << b) - 1;
315 let end_b = ((val as u64) + m) & !m;
316 if end_b + m < (val as u64) + (rng as u64) {
317 end = end_b as u32;
318 break;
319 }
320 }
321 // Flush `end` through the carry buffer, 9 bits (top of `end`) at
322 // a time.
323 while end != 0 {
324 self.carry_out(end >> 23);
325 end = (end << 8) & 0x7FFF_FFFF;
326 }
327 // Flush the buffered byte to the output (§5.1.5): if `rem` holds
328 // a real non-zero byte, or a carry run is pending, emit 9 zero
329 // bits.
330 if (self.rem != -1 && self.rem != 0) || self.ext > 0 {
331 self.carry_out(0);
332 }
333 // Append the raw bits (§5.1.3) as a disjoint tail. The §5.1.5
334 // `end` finalization commits the range value to the front bytes
335 // and relies on the decoder reading TRAILING ZEROS beyond them
336 // (the chosen `end` maximizes trailing zero bits). The decoder's
337 // forward range reader runs up to `RANGE_LOOKAHEAD_BYTES` bytes
338 // ahead of the committed data — its §4.1.1 initialization alone
339 // pre-reads a full range window before any symbol — so those
340 // lookahead positions MUST read as zero. When raw bits are
341 // present they occupy the buffer tail; a zero pad of one full
342 // range window separates them from the range data so the range
343 // reader's lookahead never consumes a raw byte. The raw region
344 // is laid out so the decoder's back-to-front raw reader (§4.1.4)
345 // sees `end_bytes[0]` (the first-emitted 8 raw bits) as the very
346 // last byte, then earlier full bytes, then the partial window
347 // byte (the last-emitted, fewer-than-8 bits) closest to the pad.
348 let mut out = self.buf;
349 let have_raw = self.nend_bits > 0 || !self.end_bytes.is_empty();
350 if have_raw {
351 out.resize(out.len() + Self::RANGE_LOOKAHEAD_BYTES, 0);
352 if self.nend_bits > 0 {
353 out.push(self.end_window as u8);
354 }
355 for &b in self.end_bytes.iter().rev() {
356 out.push(b);
357 }
358 }
359 out
360 }
361
362 // ----- internal helpers -----
363
364 /// `ec_enc_normalize` per RFC 6716 §5.1.1.1: while `rng <= 2**23`,
365 /// spill the top 9 bits of `val` to the carry buffer and shift both
366 /// `val` and `rng` left by 8.
367 fn normalize(&mut self) {
368 while self.rng <= Self::RNG_MIN {
369 self.carry_out(self.val >> 23);
370 self.val = (self.val << 8) & 0x7FFF_FFFF;
371 self.rng <<= 8;
372 self.nbits_total = self.nbits_total.saturating_add(8);
373 }
374 }
375
376 /// `ec_enc_carry_out` per RFC 6716 §5.1.1.2. Takes a 9-bit value
377 /// `c` (8 data bits + 1 carry bit).
378 fn carry_out(&mut self, c: u32) {
379 if c == 0xFF {
380 // All-ones data with no carry: defer as a potential carry
381 // run.
382 self.ext += 1;
383 return;
384 }
385 let b = c >> 8; // carry bit, 0 or 1
386 if self.rem >= 0 {
387 self.buf.push((self.rem as u32 + b) as u8);
388 }
389 if self.ext > 0 {
390 // Resolve the deferred 255-run: 0x00 if the carry
391 // propagates, 0xFF otherwise.
392 let fill = if b != 0 { 0x00 } else { 0xFF };
393 for _ in 0..self.ext {
394 self.buf.push(fill);
395 }
396 self.ext = 0;
397 }
398 self.rem = (c & 0xFF) as i32;
399 }
400}
401
402#[cfg(test)]
403mod tests {
404 use super::*;
405 use crate::range_decoder::RangeDecoder;
406
407 /// A tiny deterministic PRNG so the fuzz roundtrips need no external
408 /// crate. Not cryptographic; only used to drive symbol choices.
409 struct Lcg(u64);
410 impl Lcg {
411 fn next_u32(&mut self) -> u32 {
412 // Numerical Recipes LCG constants.
413 self.0 = self
414 .0
415 .wrapping_mul(6364136223846793005)
416 .wrapping_add(1442695040888963407);
417 (self.0 >> 32) as u32
418 }
419 fn below(&mut self, n: u32) -> u32 {
420 if n == 0 {
421 0
422 } else {
423 self.next_u32() % n
424 }
425 }
426 }
427
428 /// §5.1: a freshly-initialized encoder reports the same `tell()` as a
429 /// freshly-initialized decoder: 1 bit.
430 #[test]
431 fn init_tell_is_one() {
432 let enc = RangeEncoder::new();
433 let dec = RangeDecoder::new(&[]);
434 assert_eq!(enc.tell(), 1);
435 assert_eq!(enc.tell(), dec.tell());
436 // tell_frac reports 1/8th bits: 1 whole bit == 8 eighths.
437 assert_eq!(enc.tell_frac(), 8);
438 assert_eq!(enc.tell_frac(), dec.tell_frac());
439 }
440
441 /// §5.1.2.3 / §4.1.3.3: encode a sequence of icdf symbols and decode
442 /// them back — the decoded indices must match exactly.
443 #[test]
444 fn roundtrip_icdf() {
445 // A valid inverse-CDF table (strictly decreasing, terminated by
446 // 0) with ftb = 8, i.e. ft = 256.
447 let icdf: [u8; 4] = [200, 120, 40, 0];
448 let ftb = 8;
449 let symbols = [0usize, 3, 1, 2, 2, 0, 1, 3, 3, 0, 2, 1];
450 let mut enc = RangeEncoder::new();
451 for &k in &symbols {
452 enc.enc_icdf(k, &icdf, ftb);
453 }
454 let bytes = enc.finish();
455 let mut dec = RangeDecoder::new(&bytes);
456 for &k in &symbols {
457 assert_eq!(dec.dec_icdf(&icdf, ftb) as usize, k);
458 }
459 assert!(!dec.has_error());
460 }
461
462 /// §5.1.2.2 / §4.1.3.2: bit_logp roundtrip.
463 #[test]
464 fn roundtrip_bit_logp() {
465 let bits = [
466 true, false, false, true, true, true, false, true, false, false,
467 ];
468 let logps = [1u32, 2, 4, 8, 3, 6, 2, 1, 5, 7];
469 let mut enc = RangeEncoder::new();
470 for (i, &bit) in bits.iter().enumerate() {
471 enc.enc_bit_logp(bit, logps[i]);
472 }
473 let bytes = enc.finish();
474 let mut dec = RangeDecoder::new(&bytes);
475 for (i, &bit) in bits.iter().enumerate() {
476 assert_eq!(dec.dec_bit_logp(logps[i]) == 1, bit);
477 }
478 assert!(!dec.has_error());
479 }
480
481 /// §5.1.3 / §4.1.4: full-width 32-bit raw reads and writes are
482 /// defined (a round-382 fuzz find: the decoder's u32 raw-bit window
483 /// overflowed its shifts on a 32-bit read).
484 #[test]
485 fn roundtrip_raw_bits_32_wide() {
486 let vals: [u32; 5] = [0xFFFF_FFFF, 0, 0x8000_0001, 0xDEAD_BEEF, 0x0BAD_F00D];
487 let mut enc = RangeEncoder::new();
488 // A 3-bit write first so the 32-bit reads straddle byte seams.
489 enc.enc_bits(0b101, 3);
490 for &v in &vals {
491 enc.enc_bits(v, 32);
492 }
493 let bytes = enc.finish();
494 let mut dec = RangeDecoder::new(&bytes);
495 assert_eq!(dec.dec_bits(3), 0b101);
496 for &v in &vals {
497 assert_eq!(dec.dec_bits(32), v);
498 }
499 assert!(!dec.has_error());
500 }
501
502 /// §5.1.3 / §4.1.4: raw-bit roundtrip, mixed widths.
503 #[test]
504 fn roundtrip_raw_bits() {
505 let vals: [(u32, u32); 6] = [
506 (1, 1),
507 (0b101, 3),
508 (0xAB, 8),
509 (0x1234, 16),
510 (0, 4),
511 (0x7F, 7),
512 ];
513 let mut enc = RangeEncoder::new();
514 for &(v, b) in &vals {
515 enc.enc_bits(v, b);
516 }
517 let bytes = enc.finish();
518 let mut dec = RangeDecoder::new(&bytes);
519 for &(v, b) in &vals {
520 assert_eq!(dec.dec_bits(b), v);
521 }
522 assert!(!dec.has_error());
523 }
524
525 /// §5.1.4 / §4.1.5: uint roundtrip across the small (ftb<=8) and
526 /// large (ftb>8, raw-bit tail) paths, interleaved.
527 #[test]
528 fn roundtrip_uint() {
529 let cases: [(u32, u32); 8] = [
530 (0, 1),
531 (3, 4),
532 (200, 256),
533 (1000, 1024),
534 (65535, 65536),
535 (7, 100),
536 (123456, 1_000_000),
537 (0, 300),
538 ];
539 let mut enc = RangeEncoder::new();
540 for &(t, ft) in &cases {
541 enc.enc_uint(t, ft);
542 }
543 let bytes = enc.finish();
544 let mut dec = RangeDecoder::new(&bytes);
545 for &(t, ft) in &cases {
546 assert_eq!(dec.dec_uint(ft).unwrap(), t);
547 }
548 assert!(!dec.has_error());
549 }
550
551 /// §5.1.1: generic ec_encode roundtrip using a small uniform model,
552 /// decoded via the split ec_decode / ec_dec_update path. Encoder and
553 /// decoder `rng` are compared symbol-for-symbol via the §5.1.6
554 /// `tell()` cross-check (`tell` is a pure function of `rng` and the
555 /// symbol-count-driven `nbits_total`, which both sides track
556 /// identically).
557 #[test]
558 fn roundtrip_ec_encode_uniform() {
559 let ft = 11u32; // arbitrary non-power-of-two
560 let symbols = [0u32, 10, 5, 3, 7, 1, 9, 2, 8, 4, 6, 0, 10, 5];
561 let mut enc = RangeEncoder::new();
562 let mut enc_tell = Vec::new();
563 for &k in &symbols {
564 enc.encode(k, k + 1, ft);
565 enc_tell.push(enc.tell());
566 }
567 let bytes = enc.finish();
568 let mut dec = RangeDecoder::new(&bytes);
569 for (i, &k) in symbols.iter().enumerate() {
570 let fs = dec.ec_decode(ft);
571 // Uniform model: fs directly identifies the symbol here.
572 assert_eq!(fs, k);
573 dec.ec_dec_update(fs, fs + 1, ft);
574 assert_eq!(dec.tell(), enc_tell[i], "tell (rng) desync at symbol {i}");
575 }
576 assert!(!dec.has_error());
577 }
578
579 /// §5.1.6: `tell()` / `tell_frac()` track the decoder bit-for-bit.
580 #[test]
581 fn tell_matches_decoder() {
582 let icdf: [u8; 3] = [170, 50, 0];
583 let symbols = [0usize, 2, 1, 1, 0, 2, 2, 1, 0];
584 let mut enc = RangeEncoder::new();
585 let mut enc_tell = Vec::new();
586 let mut enc_tell_frac = Vec::new();
587 for &k in &symbols {
588 enc.enc_icdf(k, &icdf, 8);
589 enc_tell.push(enc.tell());
590 enc_tell_frac.push(enc.tell_frac());
591 }
592 let bytes = enc.finish();
593 let mut dec = RangeDecoder::new(&bytes);
594 for (i, &k) in symbols.iter().enumerate() {
595 assert_eq!(dec.dec_icdf(&icdf, 8) as usize, k);
596 assert_eq!(dec.tell(), enc_tell[i], "tell desync at {i}");
597 assert_eq!(dec.tell_frac(), enc_tell_frac[i], "tell_frac desync at {i}");
598 }
599 }
600
601 /// Randomized fuzz: mix icdf / bit_logp / uint / raw-bit symbols and
602 /// require the decoder to recover every one across many seeds.
603 #[test]
604 fn fuzz_mixed_roundtrip() {
605 let icdf: [u8; 5] = [220, 150, 90, 30, 0];
606 for seed in 0..5000u64 {
607 let mut rng = Lcg(seed.wrapping_mul(0x9E3779B97F4A7C15).wrapping_add(1));
608 let count = 8 + rng.below(60);
609 let mut ops: Vec<u8> = Vec::new();
610 let mut icdf_syms: Vec<usize> = Vec::new();
611 let mut logp_bits: Vec<(bool, u32)> = Vec::new();
612 let mut uint_vals: Vec<(u32, u32)> = Vec::new();
613 let mut raw_vals: Vec<(u32, u32)> = Vec::new();
614
615 let mut enc = RangeEncoder::new();
616 for _ in 0..count {
617 match rng.below(4) {
618 0 => {
619 let k = rng.below(4) as usize; // 0..=3 valid symbols
620 enc.enc_icdf(k, &icdf, 8);
621 ops.push(0);
622 icdf_syms.push(k);
623 }
624 1 => {
625 let bit = rng.below(2) == 1;
626 let logp = 1 + rng.below(8);
627 enc.enc_bit_logp(bit, logp);
628 ops.push(1);
629 logp_bits.push((bit, logp));
630 }
631 2 => {
632 let ft = 2 + rng.below(1 << 20);
633 let t = rng.below(ft);
634 enc.enc_uint(t, ft);
635 ops.push(2);
636 uint_vals.push((t, ft));
637 }
638 _ => {
639 let b = 1 + rng.below(16);
640 let v = rng.next_u32() & if b >= 32 { !0 } else { (1u32 << b) - 1 };
641 enc.enc_bits(v, b);
642 ops.push(3);
643 raw_vals.push((v, b));
644 }
645 }
646 }
647 let bytes = enc.finish();
648 let mut dec = RangeDecoder::new(&bytes);
649 let (mut ii, mut li, mut ui, mut ri) = (0usize, 0usize, 0usize, 0usize);
650 for &op in &ops {
651 match op {
652 0 => {
653 assert_eq!(
654 dec.dec_icdf(&icdf, 8) as usize,
655 icdf_syms[ii],
656 "seed {seed}"
657 );
658 ii += 1;
659 }
660 1 => {
661 let (bit, logp) = logp_bits[li];
662 assert_eq!(dec.dec_bit_logp(logp) == 1, bit, "seed {seed}");
663 li += 1;
664 }
665 2 => {
666 let (t, ft) = uint_vals[ui];
667 assert_eq!(dec.dec_uint(ft).unwrap(), t, "seed {seed}");
668 ui += 1;
669 }
670 _ => {
671 let (v, b) = raw_vals[ri];
672 assert_eq!(dec.dec_bits(b), v, "seed {seed}");
673 ri += 1;
674 }
675 }
676 }
677 assert!(!dec.has_error(), "seed {seed} latched error");
678 }
679 }
680}