//! 16-bit linear to 8-bit µ-law encode table -- ITU-T G.711 (1972, reaffirmed 2000).
//!
//! The 65536-entry / 64 KB table is computed at compile time by
//! [`linear_to_mulaw`], a `const fn` encoding the standard piecewise-linear
//! companding formula. The encode hot path is a single indexed lookup --
//! branchless on the 20 ms tick.
//!
//! # The µ-law encode formula (ITU-T G.711 reference, teachable-moment)
//!
//! µ-law compresses 16-bit linear PCM to 8-bit logarithmic PCM via piecewise
//! companding -- 8 segments, each twice the quantization step of the prior.
//! The fundamental transform tracks a biased magnitude:
//!
//!   * For `s >= 0` (non-negative):  `biased = s + BIAS`
//!   * For `s < 0`  (negative):      `biased = BIAS - s`  (= BIAS + magnitude)
//!
//! where `BIAS = 0x84 = 132`. The bias has a subtle reason: the lowest
//! segment (the "near-zero" band, encoded as mantissa range [0..15]) starts
//! at `BIAS`, which guarantees segment 0 has a symmetric, centered range
//! around the zero PCM point. Without BIAS, the 8-segment decoder would
//! produce an asymmetric "near-zero" band that biases silences toward +0.
//!
//! The biased magnitude is clipped to `0x7FFF` (32767) to bound the segment
//! search -- this matches the upper end of segment 7's range (`seg_uend[7] = 0x7FFF`).
//!
//! The segment exponent is then `floor(log2(biased)) - 7`, clamped to `[0, 7]`.
//! The mantissa is the top 4 bits of `biased >> (exponent + 3)` -- i.e. the
//! high-nibble of the segment-local position.
//!
//! Finally the encoder assembles `uval = (exponent << 4) | mantissa` (7 bits,
//! MSB unset) and applies a terminal XOR mask that inverts 7 (negative) or
//! 8 (positive) bits. The mask trick is what makes µ-law "self-clocking" on
//! the wire: every consecutive byte has at least one transition (no 0x00
//! runs dominate silence on T1/E1 trunks historically).
//!
//! # Why NOT a `g711` crate dep
//!
//! Same argument as `mulaw_decode_table.rs` -- standard, ~30 lines, no
//! complexity a maintained dep would solve; learner-facing.

/// Encode bias per ITU-T G.711 §2.2 (matches `mulaw_decode_table::BIAS`).
const BIAS: i32 = 0x84;

/// Convert one 16-bit linear PCM sample to an 8-bit µ-law byte.
///
/// `const fn` so the [`LINEAR_TO_MULAW`] table is built at compile time and
/// stored as a 64 KB `static` -- the encode hot path is one indexed lookup,
/// no branchy segment search at call time.
const fn linear_to_mulaw(s: i16) -> u8 {
    let is_negative = s < 0;

    // Bias the magnitude: positive samples get `s + BIAS`; negatives get
    // `BIAS - s` = `BIAS + |s|`. Both branches yield `biased >= BIAS` (>= 132),
    // so the segment search below never sees the degenerate biased = 0 case.
    let biased: i32 = if is_negative {
        BIAS - (s as i32)
    } else {
        (s as i32) + BIAS
    };

    // Clip to 0x7FFF (32767) per the Sun reference impl. After clipping the
    // largest biased value lives in segment 7's range (`seg_uend[7] = 0x7FFF`),
    // bounding the segment search to [0, 7].
    let biased: i32 = if biased > 0x7FFF { 0x7FFF } else { biased };

    // Segment exponent = floor(log2(biased)) - 7, clamped to [0, 7].
    //
    // `leading_zeros` on a positive `u32` returns `31 - floor(log2(x))` for
    // x > 0; we cast `biased` (provably positive -- no sign-bit ambiguity)
    // to `u32` first to avoid clippy::cast_sign_loss on the i32 path.
    let log2_biased = 31 - (biased as u32).leading_zeros() as i32;
    // `i32::max` / `i32::min` aren't const fn stable as of Rust 1.85; the
    // equivalent clamp via if/else is the canonical const-eval workaround
    // (and unavoidable here -- no const trait-method dispatch available
    // yet without unstable features).
    let exponent = if log2_biased < 7 {
        0
    } else if log2_biased > 14 {
        7
    } else {
        log2_biased - 7
    };

    // Mantissa = top 4 bits of the segment-local position. Shifting right by
    // `exponent + 3` aligns the segment's lowest 3 bits to the bottom of the
    // u32 (discarded), then the next 4 bits are the mantissa.
    let mantissa = ((biased >> (exponent + 3)) & 0x0F) as u8;
    let uval = ((exponent as u8) << 4) | mantissa;

    // Terminal XOR mask: 0xFF for positive (inverts all 8 bits -- MSB
    // becomes 1), 0x7F for negative (inverts bits 0..6, preserves MSB as 0).
    // This is the µ-law wire convention: stored byte MSB = 1 iff the original
    // PCM sample was non-negative (the encoder's guaranteed-transition trick
    // keeps T1/E1 line codes alive on silence runs).
    let mask: u8 = if is_negative { 0x7F } else { 0xFF };
    uval ^ mask
}

/// 65536-entry µ-law encode table (one slot per possible 16-bit PCM value).
///
/// The 64 KB binary footprint is trivial on modern hardware; the L1 trade-off
/// favors hot-path speed (one indexed lookup vs ~8 iterations of a segment
/// search). The const-eval initializer runs at compile time -- no runtime cost.
#[rustfmt::skip]
pub static LINEAR_TO_MULAW: [u8; 65536] = {
    let mut t = [0u8; 65536];
    let mut i = 0;
    while i < 65536 {
        t[i] = linear_to_mulaw(i as i16);
        i += 1;
    }
    t
};
