use crate::codec::Decoder;
use crate::codec::Encoder;
use crate::h3::Http3Error;
use crate::h3::Result;
pub fn encode_int(mut i: u64, first: u8, n: usize, mut buf: &mut [u8]) -> Result<usize> {
let buf_len = buf.len();
let mask = 2u64.pow(n as u32) - 1;
if i < mask {
buf.write_u8(first | i as u8)?;
return Ok(buf_len - buf.len());
}
buf.write_u8(first | mask as u8)?;
i -= mask;
while i >= 128 {
buf.write_u8((i % 128 + 128) as u8)?;
i >>= 7;
}
buf.write_u8(i as u8)?;
Ok(buf_len - buf.len())
}
pub fn decode_int(mut buf: &[u8], n: usize) -> Result<(u64, usize)> {
let buf_len = buf.len();
let mask = 2u64.pow(n as u32) - 1;
let mut val = u64::from(buf.read_u8()?);
val &= mask;
if val < mask {
return Ok((val, 1));
}
let mut shift = 0;
while !buf.is_empty() {
let byte = buf.read_u8()?;
let inc = u64::from(byte & 0x7f)
.checked_shl(shift)
.ok_or(Http3Error::QpackDecompressionFailed)?;
val = val
.checked_add(inc)
.ok_or(Http3Error::QpackDecompressionFailed)?;
shift += 7;
if byte & 0x80 == 0 {
return Ok((val, buf_len - buf.len()));
}
}
Err(Http3Error::QpackDecompressionFailed)
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn prefix_int_normal() {
let cases = [
(10, 5, vec![0b01010]),
(1337, 5, vec![0b11111, 0b10011010, 0b00001010]),
(42, 8, vec![0b101010]),
];
for c in cases {
let (value, prefix, mut buf) = c;
let buf_len = buf.len();
assert_eq!(decode_int(&mut buf, prefix), Ok((value, buf_len)));
let mut out = [0; 4];
let enc_len = encode_int(value, 0, prefix, &mut out).unwrap();
assert_eq!(&buf, &out[..enc_len]);
}
}
#[test]
fn decode_int_without_end_flag() {
let mut buf = vec![0b11111, 0b10011010, 0b10001010];
assert!(decode_int(&mut buf, 5).is_err());
}
#[test]
fn decode_int_empty_buf() {
let mut buf = vec![];
assert!(decode_int(&mut buf, 5).is_err());
}
#[test]
fn decode_int_too_big() {
let mut buf = vec![
0b11111, 0b10011010, 0b10001010, 0b10001010, 0b10001010, 0b10001010, 0b10001010,
0b10001010, 0b10001010,
];
assert!(decode_int(&mut buf, 5).is_err());
}
}