#![expect(
clippy::cast_possible_truncation,
reason = "u64 -> usize for decoded vector lengths"
)]
use std::io::{self, Read, Write};
use crate::s2::encoding::{read_uvarint, write_uvarint};
pub fn encode_uint_with_length(w: &mut dyn Write, value: u64, length: usize) -> io::Result<()> {
let bytes = value.to_le_bytes();
w.write_all(&bytes[..length])
}
pub fn get_uint_with_length(data: &[u8], length: usize) -> u64 {
let mut buf = [0u8; 8];
buf[..length].copy_from_slice(&data[..length]);
u64::from_le_bytes(buf)
}
pub fn decode_uint_with_length(r: &mut dyn Read, length: usize) -> io::Result<u64> {
if length == 0 {
return Ok(0);
}
let mut buf = [0u8; 8];
r.read_exact(&mut buf[..length])?;
Ok(u64::from_le_bytes(buf))
}
pub fn encode_uint_vector_u32(v: &[u32], w: &mut dyn Write) -> io::Result<()> {
let one_bits: u32 = v.iter().fold(1u32, |acc, &x| acc | x);
let len = byte_length_u32(one_bits);
let size_len = (v.len() as u64 * 4) | (len as u64 - 1);
write_uvarint(w, size_len)?;
for &x in v {
encode_uint_with_length(w, u64::from(x), len)?;
}
Ok(())
}
pub fn encode_uint_vector_u64(v: &[u64], w: &mut dyn Write) -> io::Result<()> {
let one_bits: u64 = v.iter().fold(1u64, |acc, &x| acc | x);
let len = byte_length_u64(one_bits);
let size_len = (v.len() as u64 * 8) | (len as u64 - 1);
write_uvarint(w, size_len)?;
for &x in v {
encode_uint_with_length(w, x, len)?;
}
Ok(())
}
const MAX_DECODE_COUNT: usize = 50_000_000;
pub fn decode_uint_vector_u32(r: &mut dyn Read) -> io::Result<Vec<u32>> {
let size_len = read_uvarint(r)?;
let count = (size_len / 4) as usize; if count > MAX_DECODE_COUNT {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
"uint vector too large",
));
}
let len = ((size_len & 3) + 1) as usize;
let mut result = Vec::with_capacity(count);
for _ in 0..count {
result.push(decode_uint_with_length(r, len)? as u32);
}
Ok(result)
}
pub fn decode_uint_vector_u64(r: &mut dyn Read) -> io::Result<Vec<u64>> {
let size_len = read_uvarint(r)?;
let count = (size_len / 8) as usize; if count > MAX_DECODE_COUNT {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
"uint vector too large",
));
}
let len = ((size_len & 7) + 1) as usize;
let mut result = Vec::with_capacity(count);
for _ in 0..count {
result.push(decode_uint_with_length(r, len)?);
}
Ok(result)
}
fn byte_length_u32(v: u32) -> usize {
if v == 0 {
1
} else {
(32 - v.leading_zeros() as usize).div_ceil(8)
}
}
fn byte_length_u64(v: u64) -> usize {
if v == 0 {
1
} else {
(64 - v.leading_zeros() as usize).div_ceil(8)
}
}
#[cfg(test)]
mod tests {
use super::*;
fn roundtrip_u64(input: &[u64], expected_bytes: usize) {
let mut buf = Vec::new();
encode_uint_vector_u64(input, &mut buf).unwrap();
assert_eq!(buf.len(), expected_bytes, "encoded size for {input:?}");
let decoded = decode_uint_vector_u64(&mut buf.as_slice()).unwrap();
assert_eq!(decoded, input);
}
fn roundtrip_u32(input: &[u32], expected_bytes: usize) {
let mut buf = Vec::new();
encode_uint_vector_u32(input, &mut buf).unwrap();
assert_eq!(buf.len(), expected_bytes, "encoded size for {input:?}");
let decoded = decode_uint_vector_u32(&mut buf.as_slice()).unwrap();
assert_eq!(decoded, input);
}
#[test]
fn test_empty() {
roundtrip_u32(&[], 1);
}
#[test]
fn test_zero() {
roundtrip_u64(&[0], 2);
}
#[test]
fn test_repeated_zeros_u16_equiv() {
roundtrip_u32(&[0, 0, 0], 4);
}
#[test]
fn test_max_int() {
roundtrip_u64(&[u64::MAX], 9);
}
#[test]
fn test_one_byte() {
roundtrip_u64(&[0, 255, 1, 254], 5);
}
#[test]
fn test_two_bytes() {
roundtrip_u64(&[0, 255, 256, 254], 9);
}
#[test]
fn test_three_bytes() {
roundtrip_u64(&[0xffffff, 0x0102, 0, 0x050403], 13);
}
#[test]
fn test_eight_bytes() {
roundtrip_u64(&[u64::MAX, 0, 0x0102030405060708], 25);
}
#[test]
fn test_roundtrip_encoding() {
let values: Vec<u64> = vec![10, 20, 30, 40];
let mut buf = Vec::new();
encode_uint_vector_u64(&values, &mut buf).unwrap();
let decoded = decode_uint_vector_u64(&mut buf.as_slice()).unwrap();
assert_eq!(decoded, values);
let mut buf2 = Vec::new();
encode_uint_vector_u64(&decoded, &mut buf2).unwrap();
assert_eq!(buf, buf2);
}
#[test]
fn test_encode_uint_with_length() {
let mut buf = Vec::new();
encode_uint_with_length(&mut buf, 0x1234, 2).unwrap();
assert_eq!(buf, vec![0x34, 0x12]);
buf.clear();
encode_uint_with_length(&mut buf, 0, 0).unwrap();
assert!(buf.is_empty());
buf.clear();
encode_uint_with_length(&mut buf, 0xABCDEF, 3).unwrap();
assert_eq!(buf, vec![0xEF, 0xCD, 0xAB]);
}
#[test]
fn test_get_uint_with_length() {
assert_eq!(get_uint_with_length(&[0x34, 0x12], 2), 0x1234);
assert_eq!(get_uint_with_length(&[0xEF, 0xCD, 0xAB], 3), 0xABCDEF);
assert_eq!(get_uint_with_length(&[], 0), 0);
}
}