use super::error::HpackError;
pub fn encode_integer(
value: usize,
prefix_bits: u8,
prefix_mask: u8,
buf: &mut Vec<u8>,
) -> Result<usize, HpackError> {
if prefix_bits == 0 || prefix_bits > 8 {
return Err(HpackError::InvalidPrefixSize);
}
let max_prefix_value = (1u16 << prefix_bits) - 1;
if value < max_prefix_value as usize {
if buf.is_empty() {
buf.push(0);
}
let last_idx = buf.len() - 1;
buf[last_idx] = (buf[last_idx] & !prefix_mask) | (value as u8 & prefix_mask);
Ok(0)
} else {
if buf.is_empty() {
buf.push(0);
}
let last_idx = buf.len() - 1;
buf[last_idx] = (buf[last_idx] & !prefix_mask) | prefix_mask;
let mut remaining = value - max_prefix_value as usize;
let mut bytes_written = 0;
while remaining >= 128 {
buf.push((remaining % 128 + 128) as u8);
remaining /= 128;
bytes_written += 1;
}
buf.push(remaining as u8);
bytes_written += 1;
Ok(bytes_written)
}
}
pub fn decode_integer(
data: &[u8],
prefix_bits: u8,
prefix_mask: u8,
) -> Result<(usize, usize), HpackError> {
if data.is_empty() {
return Err(HpackError::UnexpectedEof);
}
if prefix_bits == 0 || prefix_bits > 8 {
return Err(HpackError::InvalidPrefixSize);
}
let prefix_value = (data[0] & prefix_mask) as usize;
let max_prefix_value = (1usize << prefix_bits) - 1;
if prefix_value < max_prefix_value {
Ok((prefix_value, 0))
} else {
let mut value = max_prefix_value;
let mut shift = 0;
let mut pos = 1;
loop {
if pos >= data.len() {
return Err(HpackError::UnexpectedEof);
}
let byte = data[pos];
value += ((byte & 0x7F) as usize) << shift;
shift += 7;
pos += 1;
if (byte & 0x80) == 0 {
break;
}
if shift > 28 {
return Err(HpackError::IntegerOverflow);
}
}
Ok((value, pos - 1))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_encode_small_integer() {
let mut buf = vec![0x00];
encode_integer(10, 5, 0x1F, &mut buf).unwrap();
assert_eq!(buf[0] & 0x1F, 10);
}
#[test]
fn test_encode_large_integer() {
let mut buf = vec![0x00];
encode_integer(1337, 5, 0x1F, &mut buf).unwrap();
assert_eq!(buf[0] & 0x1F, 0x1F);
assert_eq!(buf.len(), 3);
assert_eq!(buf[1], 0x9A);
assert_eq!(buf[2], 0x0A);
}
#[test]
fn test_decode_small_integer() {
let data = [0x0A];
let (value, consumed) = decode_integer(&data, 5, 0x1F).unwrap();
assert_eq!(value, 10);
assert_eq!(consumed, 0);
}
#[test]
fn test_decode_large_integer() {
let mut buf = vec![0x00];
encode_integer(1337, 5, 0x1F, &mut buf).unwrap();
buf[0] |= 0xE0;
let (value, consumed) = decode_integer(&buf, 5, 0x1F).unwrap();
assert_eq!(value, 1337);
assert_eq!(consumed, 2);
}
#[test]
fn test_rfc_example_10() {
let mut buf = vec![0x00];
encode_integer(10, 5, 0x1F, &mut buf).unwrap();
assert_eq!(buf[0] & 0x1F, 10);
}
#[test]
fn test_rfc_example_1337() {
let mut buf = vec![0x00];
encode_integer(1337, 5, 0x1F, &mut buf).unwrap();
assert_eq!(buf[0] & 0x1F, 0x1F); assert_eq!(buf[1], 0x9A); assert_eq!(buf[2], 0x0A); }
}