compactly 0.1.8

Compactly encode data types using adaptive arithmetic coding
Documentation
# Plan: `decode_until_true` for the integer leading-zero loop

> OPTIMIZING.md TODO #5 — rated **highest value / dev-time** alongside #2.
> The biggest remaining integer-decode lever in the coder itself; directly speeds
> the primary `just-decompress` benchmark.

## Context

`Normal` unsigned/signed integer decode finds the top set bit by decoding
successive `leading_zero[i]` contexts until one comes up `true`
([ints.rs:68-78](../src/v2/ints.rs#L68-L78), signed magnitude loop at
[ints.rs:460-486](../src/v2/ints.rs#L460-L486)). This is the dominant per-value
loop and is exactly what `just-decompress` (random `Vec<u64>`,
[src/bin/just-decompress.rs](../src/bin/just-decompress.rs)) runs 5000×.

It is **data-dependent** (the count is unknown up front), so the fixed-`N`
`decode_bits` batch can't cover it. A dedicated method lets the coder keep
`state`/`value`/`bytes` register-resident across the whole search instead of
re-reading the decoder every bit — the same residency win the fused `decode_bits`
already captured for independent bits ([ans.rs:215](../src/v2/ans.rs#L215),
[arith.rs:333](../src/v2/arith.rs#L333)).

## Change

### 1. New `EntropyDecoder` method (in [src/v2/mod.rs]../src/v2/mod.rs)

```rust
/// Decode bits against successive contexts until one is `true`; return the count
/// of leading `false`s (== index of the first `true`). If all `contexts` decode
/// `false`, return `contexts.len()` so the caller can take its fallback path.
/// Each consumed context is adapted.
fn decode_until_true(&mut self, contexts: &mut [BitContext]) -> usize {
    for (i, ctx) in contexts.iter_mut().enumerate() {
        if self.decode_bit(ctx) { return i; }
    }
    contexts.len()
}
```

### 2. Override on each coder (the win)

`Ans`/`Range`: `state`/(`value`)/`bytes` in locals, loop `decode_step` + `adapt`,
**early-return** on the first `true`, write locals back. Same helper/pattern as
the existing `decode_bits` overrides.

### 3. Rewire the integer call sites (the subtle part)

The loop consumes `leading_zero[$bits-1-lz]` for `lz = 0,1,2,…` — i.e. the array
**in reverse** — and stops early at `lz == $bits-8` to switch to the `u8` path.
The live slots are indices `8..$bits` (56 of them for `u64`).

Recommended approach (**reorder the array's semantics** so index `i` = "i-th bit
consumed"):

- This is a format-neutral relabel: the leading-zero contexts are independent, so
  consistently reordering indices on **both** encode and decode changes nothing
  about the emitted bits or adaptation ⇒ sizes unchanged.
- Decode becomes:
  ```rust
  let lz = reader.decode_until_true(&mut ctx.leading_zero[..($bits - 8)]);
  if lz == $bits - 8 {
      // u8 fallback path, unchanged
  } else {
      let sig_bits = $bits - 1 - lz;
      // full_bytes / partial_bits decode, unchanged
  }
  ```
- Apply to all `impl_uint!` widths (u16/u32/u64/u128) and the `impl_signed!`
  magnitude loop. Mirror the index reordering in the corresponding `encode`.

(Alternative without touching encode: pass `&mut ctx.leading_zero[8..$bits]` and
have the method walk it `.rev()` internally, mapping the returned index back to
`lz`. Slightly more index math; pick whichever reads cleaner once in the code.)

`Small`-strategy integers already encode `lz` directly via `UBits<log2(bits)>`
(a #2-style tree), so they need **no** change here.

## Risk / correctness

- Bit-identical given the same consumption order ⇒ **no size change**; the
  `ints.rs` size tests (`size_u64`, `size_u32`, `size_u16`, `signed`) are the
  guardrail.
- Must preserve the early-exit-at-`$bits-8``u8` fallback exactly — that is the
  `return contexts.len()` path.

## Verification

- `cargo test` — round-trips + `ints.rs`/`signed` size asserts unchanged.
- A/B on [src/bin/just-decompress.rs]../src/bin/just-decompress.rs (`Ans`,
  random `Vec<u64>`, 5000×) and the `comparison` integer tables. `perf` cycles,
  min of pinned runs (OPTIMIZING.md methodology). Expect the clearest win of the
  three here.
- Update OPTIMIZING.md: move #5 to "Landed" with the measured cycle delta.

## Suggested order

Land **first** of the two coder methods — it is the most isolated and has the
cleanest single-benchmark A/B (`just-decompress`). The per-coder `decode_step`
override pattern it establishes is then reused by #2 (`decode_tree`).