zenith-foundation 0.1.0

Zenith 核心基础设施:统一错误类型、FrameToken 所有权令牌、FramePool、分层资源账本、恒定时间比较
Documentation
//! RFC 7541 §5.1 前缀整数编解码(HPACK / QPACK 共享唯一实现)
//!
//! HPACK(RFC 7541)与 QPACK(RFC 9204)共用同一种「前缀整数」线格式:
//! 首字节高 `prefix_bits` 位为前缀(类型标识),低 `8 - prefix_bits` 位承载
//! 低位整数;若前缀位全 1 则后续字节以 7-bit 组继续(每字节高位置 1 表示延续)。
//!
//! 本模块为全 workspace 唯一实现,禁止在 `zenith-http2` / `zenith-http3`
//! 内重复实现(历史双实现已收敛于此)。解码器 fail-closed:输入截断、
//! 扩展位过多、值超 `u64` 一律返回 `None`,绝不 panic。

/// 编码前缀整数(RFC 7541 §5.1)
///
/// - `prefix_bits`:前缀位数(1-8),越界时静默返回(调用方保证合法)。
/// - `prefix_pattern`:类型标识位,OR 到首字节高位。
///
/// 写入 `out`;`value` 为无符号整数(HPACK 用 `u32`、QPACK 用 `u64`,均无损提升)。
#[inline]
pub fn encode_prefix_integer(
    out: &mut Vec<u8>,
    value: u64,
    prefix_bits: u8,
    prefix_pattern: u8,
) {
    if prefix_bits == 0 || prefix_bits > 8 {
        return;
    }
    let mask = (1u64 << prefix_bits) - 1;
    if value < mask {
        out.push(prefix_pattern | (value as u8));
        return;
    }
    out.push(prefix_pattern | mask as u8);
    let mut v = value - mask;
    while v >= 0x80 {
        out.push(((v as u8) & 0x7F) | 0x80);
        v >>= 7;
    }
    out.push(v as u8);
}

/// 解码前缀整数(RFC 7541 §5.1)
///
/// 返回 `(value, consumed_bytes)`;`value` 为 `u64`(HPACK 调用方需自行收窄到 `u32`)。
///
/// # 安全(fail-closed)
/// - 输入截断 / 起始为空 → `None`
/// - 扩展位过多(`m > 56`,超出 `u64` 可承载范围)→ `None`
/// - 乘法/加法溢出 → `None`(checked 算术,杜绝 debug panic / release 回绕)
#[inline]
pub fn decode_prefix_integer(data: &[u8], prefix_bits: u8) -> Option<(u64, usize)> {
    if data.is_empty() || prefix_bits == 0 || prefix_bits > 8 {
        return None;
    }
    // 用 u16 计算 mask,避免 prefix_bits = 8 时 1u8 << 8 溢出
    let mask = ((1u16 << prefix_bits as u16) - 1) as u8;
    let first = data[0] & mask;
    let mut value = first as u64;
    if first < mask {
        return Some((value, 1));
    }
    let mut m: u32 = 0;
    let mut i: usize = 1;
    loop {
        // 扩展位过多(u64 上限):在读入下一个延续字节之前检查,
        // 超限 fail-closed,杜绝死循环 / 溢出。
        if m > 56 {
            return None;
        }
        let Some(&b) = data.get(i) else {
            return None; // 输入截断
        };
        i += 1;
        let shift = 1u64.checked_shl(m)?;
        let contribution = ((b & 0x7F) as u64).checked_mul(shift)?;
        value = value.checked_add(contribution)?;
        m = m.checked_add(7)?;
        if b & 0x80 == 0 {
            break;
        }
    }
    Some((value, i))
}

#[cfg(test)]
mod tests {
    use super::*;

    /// RFC 7541 §5.1 示例:前缀 5-bit,值 10 → 单字节 `0x0A`
    #[test]
    fn decode_small_single_byte() {
        assert_eq!(decode_prefix_integer(&[0x0A], 5), Some((10, 1)));
        assert_eq!(decode_prefix_integer(&[0x0A], 8), Some((10, 1)));
    }

    /// 8-bit 前缀整体作为值
    #[test]
    fn decode_max_prefix() {
        assert_eq!(decode_prefix_integer(&[0x2A], 8), Some((42, 1)));
    }

    /// 1337 = 31 + 26 + 10*2^7(5-bit 前缀三字节)
    #[test]
    fn decode_multi_byte() {
        let data = [0x1F, 0x9A, 0x0A];
        assert_eq!(decode_prefix_integer(&data, 5), Some((1337, 3)));
    }

    #[test]
    fn decode_empty_rejected() {
        assert_eq!(decode_prefix_integer(&[], 5), None);
        assert_eq!(decode_prefix_integer(&[0x00], 0), None);
        assert_eq!(decode_prefix_integer(&[0x00], 9), None);
    }

    /// 超长扩展字节(超过 u64 位移上限)fail-closed
    #[test]
    fn decode_overflow_rejected() {
        let data = [0x1F, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x01];
        assert_eq!(decode_prefix_integer(&data, 5), None);
    }

    /// 无终止字节(全 0xFF 延续)fail-closed,不 panic / 不死循环
    #[test]
    fn decode_never_terminating_rejected() {
        assert_eq!(decode_prefix_integer(&[0xFF; 16], 7), None);
    }

    /// 截断输入 fail-closed
    #[test]
    fn decode_truncated_rejected() {
        assert_eq!(decode_prefix_integer(&[0xFF], 7), None);
    }

    /// 编码/解码往返一致性(含 u64 大值)
    #[test]
    fn encode_decode_roundtrip() {
        let cases: &[(u64, u8, u8)] = &[
            (5, 7, 0x00),
            (10, 5, 0x00),
            (127, 7, 0x00),
            (128, 7, 0x00),
            (1337, 7, 0x00),
            (65535, 7, 0x00),
            (u32::MAX as u64, 7, 0x00),
            // 最大可解码值:需 shift 56(bit 62),超过需 shift 63 的值(如 u64::MAX)
            // 会被 `m > 56` 防线拒绝(与 QPACK 原始 fail-closed 语义一致)。
            (i64::MAX as u64, 7, 0x00),
            (42, 8, 0x00),
            (1, 4, 0x10),
            (2, 6, 0x40),
            (3, 6, 0x80),
        ];
        for &(value, prefix_bits, pattern) in cases {
            let mut out = Vec::new();
            encode_prefix_integer(&mut out, value, prefix_bits, pattern);
            let (decoded, consumed) = decode_prefix_integer(&out, prefix_bits).unwrap();
            assert_eq!(decoded, value, "value {value} (prefix {prefix_bits})");
            assert_eq!(consumed, out.len());
        }
    }

    /// 前缀模式位保留在首字节高位
    #[test]
    fn encode_preserves_prefix_pattern() {
        let mut out = Vec::new();
        encode_prefix_integer(&mut out, 5, 7, 0x80);
        assert_eq!(out, vec![0x85]); // 0x80 | 5
        let mut out = Vec::new();
        encode_prefix_integer(&mut out, 1, 6, 0x40);
        assert_eq!(out, vec![0x41]); // 0x40 | 1
    }
}