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
use core::ops::{Rem, Div};
use core::cmp::Ordering;
use primitive_types::U256;

#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub enum Sign {
	Plus,
	Minus,
	NoSign,
}

const SIGN_BIT_MASK: U256 = U256([0xffffffffffffffff, 0xffffffffffffffff,
								  0xffffffffffffffff, 0x7fffffffffffffff]);

#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub struct I256(pub Sign, pub U256);

impl I256 {
	/// Zero value of I256.
	pub fn zero() -> I256 { I256(Sign::NoSign, U256::zero()) }
	/// Minimum value of I256.
	pub fn min_value() -> I256 { I256(Sign::Minus, (U256::max_value() & SIGN_BIT_MASK) + U256::from(1u64)) }
}

impl Ord for I256 {
	fn cmp(&self, other: &I256) -> Ordering {
		match (self.0, other.0) {
			(Sign::NoSign, Sign::NoSign) => Ordering::Equal,
			(Sign::NoSign, Sign::Plus) => Ordering::Less,
			(Sign::NoSign, Sign::Minus) => Ordering::Greater,
			(Sign::Minus, Sign::NoSign) => Ordering::Less,
			(Sign::Minus, Sign::Plus) => Ordering::Less,
			(Sign::Minus, Sign::Minus) => self.1.cmp(&other.1).reverse(),
			(Sign::Plus, Sign::Minus) => Ordering::Greater,
			(Sign::Plus, Sign::NoSign) => Ordering::Greater,
			(Sign::Plus, Sign::Plus) => self.1.cmp(&other.1),
		}
	}
}

impl PartialOrd for I256 {
	fn partial_cmp(&self, other: &I256) -> Option<Ordering> {
		Some(self.cmp(other))
	}
}

impl Default for I256 { fn default() -> I256 { I256::zero() } }
impl From<U256> for I256 {
	fn from(val: U256) -> I256 {
		if val == U256::zero() {
			I256::zero()
		} else if val & SIGN_BIT_MASK.into() == val {
			I256(Sign::Plus, val)
		} else {
			I256(Sign::Minus, !val + U256::from(1u64))
		}
	}
}
impl Into<U256> for I256 {
	fn into(self) -> U256 {
		let sign = self.0;
		if sign == Sign::NoSign {
			U256::zero()
		} else if sign == Sign::Plus {
			self.1
		} else {
			!self.1 + U256::from(1u64)
		}
	}
}

impl Div for I256 {
	type Output = I256;

	fn div(self, other: I256) -> I256 {
		if other == I256::zero() {
			return I256::zero();
		}

		if self == I256::min_value() && other == I256(Sign::Minus, U256::from(1u64)) {
			return I256::min_value();
		}

		let d = (self.1 / other.1) & SIGN_BIT_MASK.into();

		if d == U256::zero() {
			return I256::zero();
		}

		match (self.0, other.0) {
			(Sign::Plus, Sign::Plus) |
			(Sign::Minus, Sign::Minus) => I256(Sign::Plus, d),
			(Sign::Plus, Sign::Minus) |
			(Sign::Minus, Sign::Plus) => I256(Sign::Minus, d),
			_ => I256::zero()
		}
	}
}

impl Rem for I256 {
	type Output = I256;

	fn rem(self, other: I256) -> I256 {
		let r = (self.1 % other.1) & SIGN_BIT_MASK.into();

		if r == U256::zero() {
			return I256::zero()
		}

		I256(self.0, r)
	}
}