Unpack values from a bitpacked buffer. Returns the unpacked `Vec `. Uses the scalar path. For SIMD-accelerated unpacking, use `super::simd_unpack`.
(buf: &[u8])
| 75 | /// Returns the unpacked `Vec<u32>`. Uses the scalar path. |
| 76 | /// For SIMD-accelerated unpacking, use `super::simd_unpack`. |
| 77 | pub fn unpack(buf: &[u8]) -> Vec<u32> { |
| 78 | if buf.len() < 3 { |
| 79 | return Vec::new(); |
| 80 | } |
| 81 | |
| 82 | let num_values = u16::from_le_bytes([buf[0], buf[1]]) as usize; |
| 83 | let bit_width = buf[2]; |
| 84 | |
| 85 | if num_values == 0 || bit_width == 0 { |
| 86 | return vec![0; num_values]; |
| 87 | } |
| 88 | |
| 89 | let mask = if bit_width >= 32 { |
| 90 | u32::MAX |
| 91 | } else { |
| 92 | (1u32 << bit_width) - 1 |
| 93 | }; |
| 94 | |
| 95 | let data = &buf[3..]; |
| 96 | let mut values = Vec::with_capacity(num_values); |
| 97 | let mut bit_pos = 0u64; |
| 98 | |
| 99 | for _ in 0..num_values { |
| 100 | let byte_idx = (bit_pos / 8) as usize; |
| 101 | let bit_offset = (bit_pos % 8) as u32; |
| 102 | |
| 103 | // Read up to 8 bytes starting at byte_idx (handles spanning). |
| 104 | let mut wide_bytes = [0u8; 8]; |
| 105 | let avail = data.len().saturating_sub(byte_idx).min(8); |
| 106 | wide_bytes[..avail].copy_from_slice(&data[byte_idx..byte_idx + avail]); |
| 107 | let wide = u64::from_le_bytes(wide_bytes); |
| 108 | |
| 109 | let val = ((wide >> bit_offset) as u32) & mask; |
| 110 | values.push(val); |
| 111 | |
| 112 | bit_pos += bit_width as u64; |
| 113 | } |
| 114 | |
| 115 | values |
| 116 | } |
| 117 | |
| 118 | #[cfg(test)] |
| 119 | mod tests { |