use super::{
pack_2bit, pack_3bit, pack_4bit, unpack_2bit, unpack_3bit, unpack_4bit, PACK_2BIT_GROUP_SIZE,
PACK_3BIT_BYTES, PACK_3BIT_GROUP_SIZE, PACK_4BIT_GROUP_SIZE,
};
pub(super) fn num_2bit_groups(len: usize) -> usize {
len / PACK_2BIT_GROUP_SIZE
}
pub(super) fn has_2bit_remainder(len: usize) -> bool {
len % PACK_2BIT_GROUP_SIZE != 0
}
pub(super) fn packed_2bit_capacity(num_groups: usize, has_remainder: bool) -> usize {
num_groups + usize::from(has_remainder)
}
pub(super) fn chunk_to_2bit_array(chunk: &[u8]) -> [u8; PACK_2BIT_GROUP_SIZE] {
chunk.try_into().expect("chunk size matches group size")
}
pub(super) fn pad_remainder_2bit(tail: &[u8]) -> [u8; PACK_2BIT_GROUP_SIZE] {
let mut padded = [0u8; PACK_2BIT_GROUP_SIZE];
padded[..tail.len()].copy_from_slice(tail);
padded
}
pub(super) fn num_3bit_groups(len: usize) -> usize {
len / PACK_3BIT_GROUP_SIZE
}
pub(super) fn has_3bit_remainder(len: usize) -> bool {
len % PACK_3BIT_GROUP_SIZE != 0
}
pub(super) fn packed_3bit_capacity(num_groups: usize, has_remainder: bool) -> usize {
let remainder_bytes = if has_remainder { PACK_3BIT_BYTES } else { 0 };
num_groups * PACK_3BIT_BYTES + remainder_bytes
}
pub(super) fn chunk_to_3bit_array(chunk: &[u8]) -> [u8; PACK_3BIT_GROUP_SIZE] {
chunk.try_into().expect("chunk size matches group size")
}
pub(super) fn pad_remainder_3bit(tail: &[u8]) -> [u8; PACK_3BIT_GROUP_SIZE] {
let mut padded = [0u8; PACK_3BIT_GROUP_SIZE];
padded[..tail.len()].copy_from_slice(tail);
padded
}
pub(super) fn chunk_to_packed_3bit_array(chunk: &[u8]) -> [u8; PACK_3BIT_BYTES] {
chunk.try_into().expect("chunk size matches group size")
}
pub(super) fn num_4bit_pairs(len: usize) -> usize {
len / PACK_4BIT_GROUP_SIZE
}
pub(super) fn has_4bit_remainder(len: usize) -> bool {
len % PACK_4BIT_GROUP_SIZE != 0
}
pub(super) fn packed_4bit_capacity(num_pairs: usize, has_remainder: bool) -> usize {
num_pairs + usize::from(has_remainder)
}
pub(super) fn chunk_to_4bit_array(pair: &[u8]) -> [u8; PACK_4BIT_GROUP_SIZE] {
pair.try_into().expect("chunk size matches group size")
}
pub(super) fn trailing_4bit_pair(last: u8) -> [u8; PACK_4BIT_GROUP_SIZE] {
[last, 0]
}
fn pack_indices_chunked<F, R>(
indices: &[u8],
group_size: usize,
capacity: usize,
mut pack_group: F,
mut pack_remainder: R,
) -> Vec<u8>
where
F: FnMut(&[u8], &mut Vec<u8>),
R: FnMut(&[u8], &mut Vec<u8>),
{
let mut packed = Vec::with_capacity(capacity);
for chunk in indices.chunks_exact(group_size) {
pack_group(chunk, &mut packed);
}
let mut handle_tail = || {
let tail = indices.chunks_exact(group_size).remainder();
if tail.is_empty() {
return;
}
pack_remainder(tail, &mut packed);
};
handle_tail();
packed
}
pub fn pack_indices_2bit(indices: &[u8]) -> Vec<u8> {
pack_indices_chunked(
indices,
PACK_2BIT_GROUP_SIZE,
packed_2bit_capacity(
num_2bit_groups(indices.len()),
has_2bit_remainder(indices.len()),
),
|chunk, out| out.push(pack_2bit(&chunk_to_2bit_array(chunk))),
|tail, out| out.push(pack_2bit(&pad_remainder_2bit(tail))),
)
}
pub fn unpack_indices_2bit(packed: &[u8], count: usize) -> Vec<u8> {
let mut result = Vec::with_capacity(count);
for &byte in packed {
let vals = unpack_2bit(byte);
result.extend_from_slice(&vals);
}
result.truncate(count);
result
}
pub fn pack_indices_3bit(indices: &[u8]) -> Vec<u8> {
pack_indices_chunked(
indices,
PACK_3BIT_GROUP_SIZE,
packed_3bit_capacity(
num_3bit_groups(indices.len()),
has_3bit_remainder(indices.len()),
),
|chunk, out| out.extend_from_slice(&pack_3bit(&chunk_to_3bit_array(chunk))),
|tail, out| out.extend_from_slice(&pack_3bit(&pad_remainder_3bit(tail))),
)
}
pub fn unpack_indices_3bit(packed: &[u8], count: usize) -> Vec<u8> {
let mut result = Vec::with_capacity(count);
for chunk in packed.chunks_exact(PACK_3BIT_BYTES) {
let arr = chunk_to_packed_3bit_array(chunk);
let vals = unpack_3bit(&arr);
result.extend_from_slice(&vals);
}
result.truncate(count);
result
}
pub fn pack_indices_4bit(indices: &[u8]) -> Vec<u8> {
pack_indices_chunked(
indices,
PACK_4BIT_GROUP_SIZE,
packed_4bit_capacity(
num_4bit_pairs(indices.len()),
has_4bit_remainder(indices.len()),
),
|chunk, out| out.push(pack_4bit(&chunk_to_4bit_array(chunk))),
|tail, out| out.push(pack_4bit(&trailing_4bit_pair(tail[0]))),
)
}
pub fn unpack_indices_4bit(packed: &[u8], count: usize) -> Vec<u8> {
let mut result = Vec::with_capacity(count);
for &byte in packed {
let vals = unpack_4bit(byte);
result.extend_from_slice(&vals);
}
result.truncate(count);
result
}