#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) struct ChainChunk<'a, U> {
pub prefix: &'a [U],
pub edge: U,
}
pub(crate) fn chain_chunks<U: Copy>(units: &[U], max_prefix: usize) -> Vec<ChainChunk<'_, U>> {
let width = max_prefix + 1;
let mut chunks = Vec::with_capacity(units.len().div_ceil(width));
for chunk in units.chunks(width) {
let (prefix, last) = chunk.split_at(chunk.len() - 1);
chunks.push(ChainChunk {
prefix,
edge: last[0],
});
}
chunks
}
#[cfg(test)]
mod tests {
use super::*;
fn reassemble<U: Copy>(chunks: &[ChainChunk<'_, U>]) -> Vec<U> {
let mut out = Vec::new();
for ch in chunks {
out.extend_from_slice(ch.prefix);
out.push(ch.edge);
}
out
}
#[test]
fn chain_chunks_never_truncates_exhaustive() {
for max_prefix in 0..=14usize {
let width = max_prefix + 1;
for len in 0..=128usize {
let units: Vec<u32> = (0..len as u32)
.map(|i| i.wrapping_mul(2_654_435_761))
.collect();
let chunks = chain_chunks(&units, max_prefix);
assert_eq!(
reassemble(&chunks),
units,
"truncation/loss at len={len} max_prefix={max_prefix}"
);
for ch in &chunks {
assert!(
ch.prefix.len() <= max_prefix,
"prefix {} exceeds cap {} at len={len}",
ch.prefix.len(),
max_prefix
);
}
let expected = if len == 0 { 0 } else { len.div_ceil(width) };
assert_eq!(
chunks.len(),
expected,
"node count at len={len} max_prefix={max_prefix}"
);
let covered: usize = chunks.iter().map(|c| c.prefix.len() + 1).sum();
assert_eq!(
covered, len,
"covered != len at len={len} max_prefix={max_prefix}"
);
}
}
}
#[test]
fn chain_chunks_boundaries_char_width7() {
let mp = 6;
assert!(chain_chunks::<u32>(&[], mp).is_empty());
let u1: Vec<u32> = vec![10];
let c1 = chain_chunks(&u1, mp);
assert_eq!(c1.len(), 1);
assert_eq!(c1[0].prefix, &[] as &[u32]);
assert_eq!(c1[0].edge, 10);
let u7: Vec<u32> = (0..7).collect();
let c7 = chain_chunks(&u7, mp);
assert_eq!(c7.len(), 1);
assert_eq!(c7[0].prefix, &[0, 1, 2, 3, 4, 5]);
assert_eq!(c7[0].edge, 6);
let u8v: Vec<u32> = (0..8).collect();
let c8 = chain_chunks(&u8v, mp);
assert_eq!(c8.len(), 2);
assert_eq!(c8[0].prefix, &[0, 1, 2, 3, 4, 5]);
assert_eq!(c8[0].edge, 6);
assert_eq!(c8[1].prefix, &[] as &[u32]);
assert_eq!(c8[1].edge, 7);
let u19: Vec<u32> = (0..19).collect();
let c19 = chain_chunks(&u19, mp);
assert_eq!(c19.len(), 3);
assert_eq!(reassemble(&c19), u19);
}
}