use alloc::vec::Vec;
use super::super::FnEncoder;
use crate::compressor::core::data::Stream;
use crate::compressor::core::error::NodeError;
use crate::compressor::core::exec::NodeCx;
use crate::shared::numeric::{elements, push_le};
pub(crate) static ZIGZAG: FnEncoder = FnEncoder(zigzag);
const fn map(value: u64, bits: u32) -> u64 {
let negative = (value >> (bits - 1)) & 1;
(value << 1) ^ negative.wrapping_neg()
}
fn zigzag<'a>(cx: &mut NodeCx<'_, 'a>, inputs: &[Stream<'a>]) -> Result<(), NodeError> {
let input = &inputs[0];
let width = input.width();
let bits = 8 * width as u32;
let mut out = Vec::with_capacity(input.content_size());
for value in elements(input.bytes(), width) {
push_le(&mut out, map(value, bits), width);
}
cx.emit(0, width, out)?;
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn signed_values_interleave_by_magnitude() {
let out = |value: u64, bits: u32| map(value, bits) & (u64::MAX >> (64 - bits));
assert_eq!(out(0, 8), 0);
assert_eq!(out(0xff, 8), 1); assert_eq!(out(1, 8), 2);
assert_eq!(out(0xfe, 8), 3); assert_eq!(out(0x80, 8), 0xff); assert_eq!(out(0x7f, 8), 0xfe);
assert_eq!(out(0x8000, 16), 0xffff);
assert_eq!(out(u64::from(u32::MAX), 32), 1);
assert_eq!(out(1 << 63, 64), u64::MAX);
assert_eq!(out(u64::MAX, 64), 1);
}
}