ppv-null 0.1.2

Safe, portable, non-SIMD implementation of the crypto-simd API
Documentation
use core::ops::{Add, AddAssign, BitAnd, BitOr, BitXor, BitXorAssign, Not};
use crypto_simd::*;

macro_rules! define_vec1 {
    ($X1:ident, $word:ident) => {
        #[allow(non_camel_case_types)]
        #[derive(Copy, Clone)]
        pub struct $X1($word);
        impl $X1 {
            #[inline(always)]
            pub fn new(a: $word) -> Self {
                $X1(a)
            }
            #[inline(always)]
            pub fn rotate_right(&mut self, i: $word) {
                self.0 = self.0.rotate_right(i as u32);
            }
            #[inline(always)]
            pub fn load(xs: &[$word]) -> Self {
                debug_assert_eq!(xs.len(), 1);
                $X1(xs[0])
            }
            #[inline(always)]
            pub fn xor_store(self, xs: &mut [$word]) {
                debug_assert_eq!(xs.len(), 1);
                xs[0] ^= self.0;
            }
            #[inline(always)]
            pub fn into_inner(self) -> $word {
                self.0
            }
            #[inline(always)]
            fn swap(self, m: u128, i: u32) -> Self {
                $X1(((self.0 & m) >> i) | ((self.0) << i) & m)
            }
            #[inline(always)]
            pub fn swap1(self) -> Self {
                self.swap(0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa, 1)
            }
            #[inline(always)]
            pub fn swap2(self) -> Self {
                self.swap(0xcccccccccccccccccccccccccccccccc, 2)
            }
            #[inline(always)]
            pub fn swap4(self) -> Self {
                self.swap(0xf0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0, 4)
            }
            #[inline(always)]
            pub fn swap8(self) -> Self {
                self.swap(0xff00ff00ff00ff00ff00ff00ff00ff00, 8)
            }
            #[inline(always)]
            pub fn swap16(self) -> Self {
                self.swap(0xffff0000ffff0000ffff0000ffff0000, 16)
            }
            #[inline(always)]
            pub fn swap32(self) -> Self {
                self.swap(0xffffffff00000000ffffffff00000000, 32)
            }
            #[inline(always)]
            pub fn swap64(self) -> Self {
                $X1(self.0 << 64 | self.0 >> 64)
            }
            #[inline(always)]
            pub fn andnot(self, rhs: Self) -> Self {
                !self & rhs
            }
            #[inline(always)]
            pub fn extract(self, i: u32) -> $word {
                debug_assert_eq!(i, 0);
                self.0
            }
        }
        impl AddAssign for $X1 {
            #[inline(always)]
            fn add_assign(&mut self, rhs: Self) {
                self.0 += rhs.0;
            }
        }
        impl BitXorAssign for $X1 {
            #[inline(always)]
            fn bitxor_assign(&mut self, rhs: Self) {
                self.0 ^= rhs.0;
            }
        }
        impl BitXor for $X1 {
            type Output = Self;
            #[inline(always)]
            fn bitxor(self, rhs: Self) -> Self::Output {
                $X1(self.0 ^ rhs.0)
            }
        }
        impl BitAnd for $X1 {
            type Output = Self;
            #[inline(always)]
            fn bitand(self, rhs: Self) -> Self::Output {
                $X1(self.0 & rhs.0)
            }
        }
        impl Not for $X1 {
            type Output = Self;
            #[inline(always)]
            fn not(self) -> Self::Output {
                $X1(!self.0)
            }
        }
    };
}
macro_rules! define_vec2 {
    ($X2:ident, $word:ident) => {
        #[allow(non_camel_case_types)]
        #[derive(Copy, Clone)]
        pub struct $X2($word, $word);
        impl $X2 {
            #[inline(always)]
            pub fn new(a: $word, b: $word) -> Self {
                $X2(a, b)
            }
            #[inline(always)]
            fn map<F>(self, mut f: F) -> Self
            where
                F: FnMut($word) -> $word,
            {
                $X2(f(self.0), f(self.1))
            }
            #[inline(always)]
            fn zipmap<F>(self, rhs: Self, mut f: F) -> Self
            where
                F: FnMut($word, $word) -> $word,
            {
                $X2(f(self.0, rhs.0), f(self.1, rhs.1))
            }
            #[inline(always)]
            pub fn rotate_right(&mut self, i: $word) {
                *self = self.map(|x| $word::rotate_right(x, i as u32));
            }
            #[inline(always)]
            pub fn load(xs: &[$word]) -> Self {
                debug_assert_eq!(xs.len(), 2);
                $X2(xs[0], xs[1])
            }
            #[inline(always)]
            pub fn xor_store(self, xs: &mut [$word]) {
                debug_assert_eq!(xs.len(), 2);
                xs[0] ^= self.0;
                xs[1] ^= self.1;
            }
            #[inline(always)]
            pub fn extract(self, i: u32) -> $word {
                let x = [self.0, self.1];
                x[i as usize]
            }
            #[inline(always)]
            pub fn andnot(self, rhs: Self) -> Self {
                !self & rhs
            }
        }
        impl AddAssign for $X2 {
            #[inline(always)]
            fn add_assign(&mut self, rhs: Self) {
                *self = self.zipmap(rhs, $word::wrapping_add);
            }
        }
        impl BitXorAssign for $X2 {
            #[inline(always)]
            fn bitxor_assign(&mut self, rhs: Self) {
                *self = self.zipmap(rhs, $word::bitxor);
            }
        }
        impl BitAnd for $X2 {
            type Output = Self;
            #[inline(always)]
            fn bitand(self, rhs: Self) -> Self::Output {
                $X2(self.0 & rhs.0, self.1 & rhs.1)
            }
        }
        impl Not for $X2 {
            type Output = Self;
            #[inline(always)]
            fn not(self) -> Self::Output {
                $X2(!self.0, !self.1)
            }
        }
        impl BitOr for $X2 {
            type Output = Self;
            #[inline(always)]
            fn bitor(self, rhs: Self) -> Self::Output {
                $X2(self.0 | rhs.0, self.1 | rhs.1)
            }
        }
    };
}

macro_rules! zipmap_impl {
    ($vec:ident, $word:ident, $trait:ident, $fn:ident, $impl_fn:ident) => {
        impl $trait for $vec {
            type Output = Self;
            #[inline(always)]
            fn $fn(self, rhs: Self) -> Self::Output {
                self.zipmap(rhs, $word::$impl_fn)
            }
        }
    };
    ($vec:ident, $word:ident, $trait:ident, $fn:ident) => {
        zipmap_impl!($vec, $word, $trait, $fn, $fn);
    };
}

macro_rules! define_vec4 {
    ($X4:ident, $word:ident) => {
        #[allow(non_camel_case_types)]
        #[derive(Copy, Clone)]
        pub struct $X4($word, $word, $word, $word);
        impl $X4 {
            #[inline(always)]
            pub fn new(a: $word, b: $word, c: $word, d: $word) -> Self {
                $X4(a, b, c, d)
            }
            #[inline(always)]
            fn zipmap<F>(self, rhs: Self, mut f: F) -> Self
            where
                F: FnMut($word, $word) -> $word,
            {
                $X4(
                    f(self.0, rhs.0),
                    f(self.1, rhs.1),
                    f(self.2, rhs.2),
                    f(self.3, rhs.3),
                )
            }
            #[inline(always)]
            pub fn rotate_right(&mut self, ii: Self) -> Self {
                $X4(
                    self.0.rotate_right(ii.0 as u32),
                    self.1.rotate_right(ii.1 as u32),
                    self.2.rotate_right(ii.2 as u32),
                    self.3.rotate_right(ii.3 as u32),
                )
            }
            #[inline(always)]
            pub fn from_slice_unaligned(xs: &[$word]) -> Self {
                debug_assert_eq!(xs.len(), 4);
                $X4(xs[0], xs[1], xs[2], xs[3])
            }
            #[inline(always)]
            pub fn splat(x: $word) -> Self {
                $X4(x, x, x, x)
            }
            #[inline(always)]
            pub fn write_to_slice_unaligned(self, xs: &mut [$word]) {
                debug_assert_eq!(xs.len(), 4);
                xs[0] = self.0;
                xs[1] = self.1;
                xs[2] = self.2;
                xs[3] = self.3;
            }
            #[inline(always)]
            pub fn replace(mut self, i: usize, v: $word) -> Self {
                let xs = [&mut self.0, &mut self.1, &mut self.2, &mut self.3];
                *xs[i] = v;
                self
            }
            #[inline(always)]
            pub fn extract(self, i: usize) -> $word {
                let xs = [self.0, self.1, self.2, self.3];
                xs[i]
            }
        }
        impl AddAssign for $X4 {
            #[inline(always)]
            fn add_assign(&mut self, rhs: Self) {
                *self = self.zipmap(rhs, $word::wrapping_add);
            }
        }
        impl BitXorAssign for $X4 {
            #[inline(always)]
            fn bitxor_assign(&mut self, rhs: Self) {
                *self = self.zipmap(rhs, $word::bitxor);
            }
        }
        zipmap_impl!($X4, $word, Add, add, wrapping_add);
        zipmap_impl!($X4, $word, BitXor, bitxor);
        zipmap_impl!($X4, $word, BitOr, bitor);
        zipmap_impl!($X4, $word, BitAnd, bitand);
        impl RotateWordsRight for $X4 {
            type Output = Self;
            #[inline(always)]
            fn rotate_words_right(self, i: u32) -> Self::Output {
                debug_assert_eq!(i & !3, 0);
                match i & 3 {
                    0 => self,
                    1 => $X4(self.3, self.0, self.1, self.2),
                    2 => $X4(self.2, self.3, self.0, self.1),
                    3 => $X4(self.1, self.2, self.3, self.0),
                    _ => unreachable!(),
                }
            }
        }
        impl SplatRotateRight for $X4 {
            type Output = Self;
            #[inline(always)]
            fn splat_rotate_right(self, i: u32) -> Self::Output {
                const BITS: u32 = core::mem::size_of::<$word>() as u32 * 8;
                $X4(
                    (self.0 >> i) | (self.0 << (BITS - i)),
                    (self.1 >> i) | (self.1 << (BITS - i)),
                    (self.2 >> i) | (self.2 << (BITS - i)),
                    (self.3 >> i) | (self.3 << (BITS - i)),
                )
            }
        }
    };
}

define_vec4!(u32x4, u32);
define_vec4!(u64x4, u64);
define_vec1!(u128x1, u128);
define_vec2!(u128x2, u128);

// TODO: macroize this for other types
#[allow(non_camel_case_types)]
#[derive(Copy, Clone)]
pub struct u32x4x4(u32x4, u32x4, u32x4, u32x4);
impl u32x4x4 {
    #[inline(always)]
    fn zipmap<F>(self, rhs: Self, mut f: F) -> Self
    where
        F: FnMut(u32x4, u32x4) -> u32x4,
    {
        u32x4x4(
            f(self.0, rhs.0),
            f(self.1, rhs.1),
            f(self.2, rhs.2),
            f(self.3, rhs.3),
        )
    }
    #[inline(always)]
    pub fn from((a, b, c, d): (u32x4, u32x4, u32x4, u32x4)) -> Self {
        u32x4x4(a, b, c, d)
    }
    #[inline(always)]
    pub fn splat(a: u32x4) -> Self {
        u32x4x4(a, a, a, a)
    }
    #[inline(always)]
    pub fn into_parts(self) -> (u32x4, u32x4, u32x4, u32x4) {
        (self.0, self.1, self.2, self.3)
    }
}
zipmap_impl!(u32x4x4, u32x4, BitXor, bitxor);
zipmap_impl!(u32x4x4, u32x4, BitOr, bitor);
zipmap_impl!(u32x4x4, u32x4, BitAnd, bitand);
zipmap_impl!(u32x4x4, u32x4, Add, add);
impl BitXorAssign for u32x4x4 {
    #[inline(always)]
    fn bitxor_assign(&mut self, rhs: Self) {
        self.0 = self.0 ^ rhs.0;
        self.1 = self.1 ^ rhs.1;
        self.2 = self.2 ^ rhs.2;
        self.3 = self.3 ^ rhs.3;
    }
}
impl AddAssign for u32x4x4 {
    #[inline(always)]
    fn add_assign(&mut self, rhs: Self) {
        self.0 = self.0 + rhs.0;
        self.1 = self.1 + rhs.1;
        self.2 = self.2 + rhs.2;
        self.3 = self.3 + rhs.3;
    }
}
impl RotateWordsRight for u32x4x4 {
    type Output = Self;
    #[inline(always)]
    fn rotate_words_right(self, i: u32) -> Self::Output {
        u32x4x4(
            self.0.rotate_words_right(i),
            self.1.rotate_words_right(i),
            self.2.rotate_words_right(i),
            self.3.rotate_words_right(i),
        )
    }
}
impl SplatRotateRight for u32x4x4 {
    type Output = Self;
    #[inline(always)]
    fn splat_rotate_right(self, i: u32) -> Self::Output {
        u32x4x4(
            self.0.splat_rotate_right(i),
            self.1.splat_rotate_right(i),
            self.2.splat_rotate_right(i),
            self.3.splat_rotate_right(i),
        )
    }
}