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
112
113
114
115
116
117
118
119
120
121
122
use crate::U256;
use num_traits::{
    Bounded, FromPrimitive, MulAdd, MulAddAssign, Num, One, ToPrimitive, Unsigned, Zero,
};

impl Bounded for U256 {
    #[inline(always)]
    fn min_value() -> Self {
        Self::ZERO
    }

    #[inline(always)]
    fn max_value() -> Self {
        Self::MAX
    }
}

impl Zero for U256 {
    #[inline(always)]
    fn zero() -> Self {
        Self::ZERO
    }

    #[inline(always)]
    fn is_zero(&self) -> bool {
        self == &Self::ZERO
    }
}

impl One for U256 {
    #[inline(always)]
    fn one() -> Self {
        Self::ONE
    }

    #[inline(always)]
    fn is_one(&self) -> bool {
        self == &Self::ONE
    }
}

impl MulAdd for &U256 {
    type Output = U256;

    #[inline(always)]
    fn mul_add(self, a: Self, b: Self) -> Self::Output {
        // OPT: Fused algorithm
        (self * a) + b
    }
}

impl MulAddAssign<&U256, &U256> for U256 {
    #[inline(always)]
    fn mul_add_assign(&mut self, a: &Self, b: &Self) {
        // OPT: Fused algorithm
        *self *= a;
        *self += b;
    }
}

impl Num for U256 {
    type FromStrRadixErr = ();

    fn from_str_radix(_str: &str, _radix: u32) -> Result<Self, Self::FromStrRadixErr> {
        todo!()
    }
}

impl Unsigned for U256 {}

impl FromPrimitive for U256 {
    #[inline(always)]
    fn from_i64(n: i64) -> Option<Self> {
        Some(Self::from(n))
    }

    #[inline(always)]
    fn from_u64(n: u64) -> Option<Self> {
        Some(Self::from(n))
    }

    // TODO: fn from_u128
    // TODO: fn from_i128
}

impl ToPrimitive for U256 {
    fn to_u128(&self) -> Option<u128> {
        if *self < Self::from_limbs([0, 0, 1, 0]) {
            // Casting u64 to u128 is safe
            #[allow(clippy::cast_lossless)]
            Some((self.limb(0) as u128) | ((self.limb(1) as u128) << 64))
        } else {
            None
        }
    }

    fn to_i128(&self) -> Option<i128> {
        self.to_u128().as_ref().and_then(ToPrimitive::to_i128)
    }

    fn to_u64(&self) -> Option<u64> {
        self.to_u128().as_ref().and_then(ToPrimitive::to_u64)
    }

    fn to_i64(&self) -> Option<i64> {
        self.to_u128().as_ref().and_then(ToPrimitive::to_i64)
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::traits::{Binary, BinaryAssignRef};
    use num_traits::{NumAssign, NumAssignRef, NumRef, RefNum};

    // Assert that U256 implements a number of traits
    trait TraitBounds:
        NumAssign + NumAssignRef + NumRef + RefNum<Self> + Binary + BinaryAssignRef
    {
    }
    impl TraitBounds for U256 {}
}