use alloc::vec::Vec;
pub fn pack_i8s_to_u32s(values: Vec<i8>) -> Vec<u32> {
#[cfg(target_endian = "big")]
{
values
.chunks(4)
.map(|x| {
x.iter()
.enumerate()
.fold(0u32, |acc, (i, x)| acc | (*x as u32 & 0xFF) << (i * 8))
})
.collect()
}
#[cfg(target_endian = "little")]
{
let mut values = values;
let remainder = values.len() % 4;
if remainder != 0 {
values.extend(core::iter::repeat(0).take(4 - remainder));
}
let len = values.len() / 4;
let capacity = values.capacity() / 4;
let mut values = core::mem::ManuallyDrop::new(values);
let ptr = values.as_mut_ptr() as *mut u32;
unsafe { Vec::from_raw_parts(ptr, len, capacity) }
}
}
pub fn unpack_u32s_to_i8s(values: Vec<u32>, numel: usize) -> Vec<i8> {
#[cfg(target_endian = "big")]
{
values
.into_iter()
.enumerate()
.flat_map(|(i, packed)| {
let n = core::cmp::min(4, numel - i * 4);
(0..n).map(move |i| (packed >> (i * 8) & 0xFF) as i8)
})
.collect()
}
#[cfg(target_endian = "little")]
{
let len = values.len() * 4;
let capacity = values.capacity() * 4;
let mut values = core::mem::ManuallyDrop::new(values);
let ptr = values.as_mut_ptr() as *mut i8;
let mut vec = unsafe { Vec::from_raw_parts(ptr, len, capacity) };
let padding = len - numel;
if padding > 0 {
vec.truncate(len - padding);
}
vec
}
}
#[cfg(test)]
mod tests {
use super::*;
use alloc::vec;
#[test]
fn should_pack_i8s_to_u32() {
let packed = pack_i8s_to_u32s(vec![-128, 2, -3, 127]);
assert_eq!(packed, vec![2147287680]);
}
#[test]
fn should_pack_i8s_to_u32_padded() {
let packed = pack_i8s_to_u32s(vec![-128, 2, -3, 127, 55]);
let packed_padded = pack_i8s_to_u32s(vec![-128, 2, -3, 127, 55, 0, 0, 0]);
assert_eq!(packed, vec![2147287680, 55]);
assert_eq!(packed, packed_padded);
}
#[test]
fn should_unpack_u32s_to_i8s() {
let unpacked = unpack_u32s_to_i8s(vec![2147287680u32], 4);
assert_eq!(unpacked, vec![-128, 2, -3, 127]);
}
#[test]
fn should_unpack_u32s_to_i8s_padded() {
let unpacked = unpack_u32s_to_i8s(vec![55u32], 1);
assert_eq!(unpacked, vec![55]);
}
}