swizzler 0.1.0

Reorder values in a slice, for example to convert an image from BGRA to RGBA colors
Documentation
#![doc = include_str!("../README.md")]

/// The function that does the actual work.
fn do_copy<T: Copy>(src: &[T], dst: &mut [T], pattern: &[usize]) {
    let pattern_len = pattern.len();
    assert_eq!(src.len(), dst.len(), "src and dst need to be the same size");
    assert!(
        src.len().is_multiple_of(pattern_len),
        "length must be divisable by {}, but is {}",
        pattern_len,
        src.len()
    );
    for i in 0..src.len() / pattern_len {
        for j in 0..pattern_len {
            dst[i * pattern_len + j] = src[i * pattern_len + pattern[j]];
        }
    }
}

macro_rules! define_copy {
    ($t: ident, [$i0: literal, $i1: literal, $i2: literal, $i3: literal]) => {
        paste::paste! {
            #[doc = concat!(
                "Copy from `src` to `dst`, reordering 4 ",
                stringify!($t),
                " at a time in the pattern (",
                $i0, ", ",
                $i1, ", ",
                $i2, ", ",
                $i3, ").\n\n",
                "\n",
                "```\n",
                "let mut swizzled = [0; 8];\n",
                "swizzler::",
                stringify!($t), "::", stringify!([<"copy_" $i0 $i1 $i2 $i3>]),
                "(&[0, 1, 2, 3, 10, 11, 12, 13], &mut swizzled);\n",
                "assert_eq!(swizzled, [",
                concat!($i0, ", ", $i1, ", ", $i2, ", ", $i3), ", ",
                concat!("1", $i0, ", 1", $i1, ", 1", $i2, ", 1", $i3),
                "]);\n",
                "```\n"
            )]
            pub fn [<"copy_" $i0 $i1 $i2 $i3>](src: &[$t], dst: &mut [$t]) {
                super::do_copy(src, dst, &[$i0, $i1, $i2, $i3]);
            }
        }
    };
}

macro_rules! define_type {
    ($t:ident) => {
        #[doc = concat!("Functions for swizzling slices of `", stringify!($t), "`.")]
        pub mod $t {
            define_copy!($t, [0, 1, 2, 3]);
            define_copy!($t, [0, 1, 3, 2]);
            define_copy!($t, [0, 2, 1, 3]);
            define_copy!($t, [0, 2, 3, 1]);
            define_copy!($t, [0, 3, 1, 2]);
            define_copy!($t, [0, 3, 2, 1]);
            define_copy!($t, [1, 0, 2, 3]);
            define_copy!($t, [1, 0, 3, 2]);
            define_copy!($t, [1, 2, 0, 3]);
            define_copy!($t, [1, 2, 3, 0]);
            define_copy!($t, [1, 3, 0, 2]);
            define_copy!($t, [1, 3, 2, 0]);
            define_copy!($t, [2, 0, 1, 3]);
            define_copy!($t, [2, 0, 3, 1]);
            define_copy!($t, [2, 1, 0, 3]);
            define_copy!($t, [2, 1, 3, 0]);
            define_copy!($t, [2, 3, 0, 1]);
            define_copy!($t, [2, 3, 1, 0]);
            define_copy!($t, [3, 0, 1, 2]);
            define_copy!($t, [3, 0, 2, 1]);
            define_copy!($t, [3, 1, 0, 2]);
            define_copy!($t, [3, 1, 2, 0]);
            define_copy!($t, [3, 2, 0, 1]);
            define_copy!($t, [3, 2, 1, 0]);
        }
    };
}

#[cfg(feature = "u8")]
define_type!(u8);

#[cfg(feature = "u16")]
define_type!(u16);

#[cfg(feature = "u32")]
define_type!(u32);

/// Convert pixel color data in BGRA order to RGBA order.
///
/// Alias for [`u8::copy_2103`].
pub fn bgra_to_rgba(src: &[u8], dst: &mut [u8]) {
    u8::copy_2103(src, dst);
}

/// Convert pixel color data in RGBA order to BGRA order.
///
/// Alias for [`u8::copy_2103`].
pub fn rgba_to_bgra(src: &[u8], dst: &mut [u8]) {
    u8::copy_2103(src, dst);
}

#[cfg(test)]
mod tests {
    use super::*;

    #[cfg(feature = "u8")]
    #[test]
    fn u8_copy_2103_test() {
        let source = [10, 11, 12, 13, 20, 21, 22, 23];
        let mut target = [0; 8];
        u8::copy_2103(&source, &mut target);
        assert_eq!(target, [12, 11, 10, 13, 22, 21, 20, 23]);
    }
}