1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
use num_traits::{NumOps, One, Zero};
use std::convert::From;
use std::mem::size_of;
use std::num::Wrapping;
use std::ops::Shr;
use std::ops::{BitAnd, BitOr, BitOrAssign, BitXor, Neg, Not};

/*
 * Contents of this file heavily borrowed from or influenced by BearSSL by Thomas Pornin
 * https://www.bearssl.org/gitweb/?p=BearSSL;a=blob;f=src/inner.h
 */

#[derive(Copy, Clone)]
pub struct ConstantBool<T: NumOps + Copy>(pub T);

macro_rules! constantbool_from_impl {
    ($($t:ty)*) => ($(
        impl From<bool> for ConstantBool<$t> {
            fn from(b: bool) -> ConstantBool<$t> {
                ConstantBool(b as $t)
            }
        }
    )*)
}
constantbool_from_impl! { u32 u64 }

impl<T: NumOps + Copy + BitXor<Output = T> + One> Not for ConstantBool<T> {
    type Output = Self;

    /// Performs the unary `!` operation.
    #[inline]
    fn not(self) -> ConstantBool<T> {
        ConstantBool(self.0 ^ <T>::one())
    }
}

impl<T: NumOps + Copy + Zero> Default for ConstantBool<T> {
    #[inline]
    fn default() -> ConstantBool<T> {
        ConstantBool(<T>::zero())
    }
}

impl<T: NumOps + Copy + BitAnd<Output = T>> BitAnd for ConstantBool<T> {
    type Output = Self;
    #[inline]
    fn bitand(self, rhs: Self) -> Self {
        ConstantBool(self.0 & rhs.0)
    }
}

impl<T: NumOps + Copy + BitOr<Output = T>> BitOr for ConstantBool<T> {
    type Output = Self;
    #[inline]
    fn bitor(self, rhs: Self) -> Self {
        ConstantBool(self.0 | rhs.0)
    }
}

impl<T: NumOps + Copy + BitXor<Output = T>> BitXor for ConstantBool<T> {
    type Output = Self;
    #[inline]
    fn bitxor(self, rhs: Self) -> Self {
        ConstantBool(self.0 ^ rhs.0)
    }
}

impl<T: NumOps + Copy + BitOr<Output = T>> BitOrAssign for ConstantBool<T> {
    #[inline]
    fn bitor_assign(&mut self, rhs: Self) {
        *self = *self | rhs;
    }
}

impl<T> ConstantBool<T>
where
    Wrapping<T>: Neg<Output = Wrapping<T>> + BitOr<Output = Wrapping<T>>,
    T: NumOps
        + Copy
        + BitAnd<Output = T>
        + BitXor<Output = T>
        + BitOr<Output = T>
        + Shr<usize, Output = T>
        + One
        + Zero
        + PartialEq,
{
    ///This chooses the first value if self is 1 (true), chooses the 2nd value if the value is 0 (false).
    #[inline]
    pub fn mux(self, x: T, y: T) -> T {
        y ^ (Wrapping(self.0).neg().0 & (x ^ y))
    }
    #[inline]
    pub fn is_zero(i: T) -> Self {
        let q = Wrapping(i);
        let shift_amount = size_of::<T>() * 8 - 1;
        ConstantBool((q | q.neg()).0 >> shift_amount).not()
    }
    #[inline]
    pub fn not_zero(i: T) -> Self {
        ConstantBool(Self::is_zero(i).0 ^ <T>::one())
    }
    #[inline]
    pub fn new_true() -> Self {
        ConstantBool(<T>::one())
    }
    #[inline]
    pub fn new_false() -> Self {
        ConstantBool(<T>::zero())
    }
}