pub fn byte_shuffle(data: &[u8], typesize: usize) -> Vec<u8> {
if typesize <= 1 || data.len() < typesize {
return data.to_vec();
}
let mut out = vec![0u8; data.len()];
shuffle_into(data, &mut out, typesize);
out
}
pub fn byte_unshuffle(data: &[u8], typesize: usize) -> Vec<u8> {
if typesize <= 1 || data.len() < typesize {
return data.to_vec();
}
let mut out = vec![0u8; data.len()];
unshuffle_into(data, &mut out, typesize);
out
}
pub fn byte_shuffle_in_place(buf: &mut [u8], typesize: usize) {
if typesize <= 1 || buf.len() < typesize {
return;
}
let scratch = byte_shuffle(buf, typesize);
buf.copy_from_slice(&scratch);
}
pub fn byte_unshuffle_in_place(buf: &mut [u8], typesize: usize) {
if typesize <= 1 || buf.len() < typesize {
return;
}
let scratch = byte_unshuffle(buf, typesize);
buf.copy_from_slice(&scratch);
}
fn shuffle_into(data: &[u8], out: &mut [u8], typesize: usize) {
let n_elements = data.len() / typesize;
let tail_len = data.len() - n_elements * typesize;
for byte_idx in 0..typesize {
let band_offset = byte_idx * n_elements;
for elem_idx in 0..n_elements {
out[band_offset + elem_idx] = data[elem_idx * typesize + byte_idx];
}
}
if tail_len > 0 {
let tail_src_start = n_elements * typesize;
let tail_dst_start = typesize * n_elements;
out[tail_dst_start..tail_dst_start + tail_len]
.copy_from_slice(&data[tail_src_start..tail_src_start + tail_len]);
}
}
fn unshuffle_into(data: &[u8], out: &mut [u8], typesize: usize) {
let n_elements = data.len() / typesize;
let tail_len = data.len() - n_elements * typesize;
for byte_idx in 0..typesize {
let band_offset = byte_idx * n_elements;
for elem_idx in 0..n_elements {
out[elem_idx * typesize + byte_idx] = data[band_offset + elem_idx];
}
}
if tail_len > 0 {
let tail_src_start = typesize * n_elements;
let tail_dst_start = n_elements * typesize;
out[tail_dst_start..tail_dst_start + tail_len]
.copy_from_slice(&data[tail_src_start..tail_src_start + tail_len]);
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn shuffle_typesize_one_is_identity() {
let data: Vec<u8> = (0..32).collect();
assert_eq!(byte_shuffle(&data, 1), data);
assert_eq!(byte_unshuffle(&data, 1), data);
}
#[test]
fn shuffle_typesize_zero_is_identity() {
let data: Vec<u8> = (0..16).collect();
assert_eq!(byte_shuffle(&data, 0), data);
}
#[test]
fn shuffle_short_input_passthrough() {
let data = [1u8, 2, 3];
assert_eq!(byte_shuffle(&data, 8), data.to_vec());
}
#[test]
fn shuffle_f32_two_elements_canonical_example() {
let data = [0u8, 1, 2, 3, 4, 5, 6, 7];
let shuffled = byte_shuffle(&data, 4);
assert_eq!(shuffled, vec![0, 4, 1, 5, 2, 6, 3, 7]);
let restored = byte_unshuffle(&shuffled, 4);
assert_eq!(restored, data);
}
#[test]
fn shuffle_in_place_round_trip() {
let original: Vec<u8> = (0..64).collect();
let mut buf = original.clone();
byte_shuffle_in_place(&mut buf, 4);
assert_ne!(buf, original);
byte_unshuffle_in_place(&mut buf, 4);
assert_eq!(buf, original);
}
}