1use core::{
4 cmp::Ordering,
5 ops::{Div, Rem},
6};
7
8use crate::error::{ExitError, ExitFatal};
9#[allow(unused_imports)]
10use crate::uint::{H160, H256, U256, U256Ext};
11
12#[must_use]
14pub fn u256_to_h256(v: U256) -> H256 {
15 v.to_h256()
16}
17
18#[must_use]
20pub fn h256_to_u256(v: H256) -> U256 {
21 U256::from_h256(v)
22}
23
24#[must_use]
26pub fn u256_to_h160(v: U256) -> H160 {
27 v.to_h160()
28}
29
30pub fn u256_to_usize(v: U256) -> Result<usize, ExitError> {
32 if v > U256::USIZE_MAX {
33 return Err(ExitFatal::NotSupported.into());
34 }
35 Ok(v.low_usize())
36}
37
38#[derive(Copy, Clone, Eq, PartialEq, Debug)]
40pub enum Sign {
41 Plus,
43 Minus,
45 Zero,
47}
48
49#[derive(Copy, Clone, Eq, PartialEq, Debug)]
51pub struct I256(pub Sign, pub U256);
52
53impl I256 {
54 #[must_use]
56 pub const fn zero() -> I256 {
57 I256(Sign::Zero, U256::ZERO)
58 }
59 #[must_use]
61 pub fn min_value() -> I256 {
62 I256(
63 Sign::Minus,
64 (U256::MAX & U256::SIGN_BIT_MASK) + U256::from(1u64),
65 )
66 }
67}
68
69impl Ord for I256 {
70 fn cmp(&self, other: &I256) -> Ordering {
71 match (self.0, other.0) {
72 (Sign::Zero, Sign::Zero) => Ordering::Equal,
73 (Sign::Zero, Sign::Plus) => Ordering::Less,
74 (Sign::Zero, Sign::Minus) => Ordering::Greater,
75 (Sign::Minus, Sign::Zero) => Ordering::Less,
76 (Sign::Minus, Sign::Plus) => Ordering::Less,
77 (Sign::Minus, Sign::Minus) => self.1.cmp(&other.1).reverse(),
78 (Sign::Plus, Sign::Minus) => Ordering::Greater,
79 (Sign::Plus, Sign::Zero) => Ordering::Greater,
80 (Sign::Plus, Sign::Plus) => self.1.cmp(&other.1),
81 }
82 }
83}
84
85impl PartialOrd for I256 {
86 fn partial_cmp(&self, other: &I256) -> Option<Ordering> {
87 Some(self.cmp(other))
88 }
89}
90
91impl Default for I256 {
92 fn default() -> I256 {
93 I256::zero()
94 }
95}
96
97impl From<U256> for I256 {
98 fn from(val: U256) -> I256 {
99 if val == U256::ZERO {
100 I256::zero()
101 } else if val & U256::SIGN_BIT_MASK == val {
102 I256(Sign::Plus, val)
103 } else {
104 I256(Sign::Minus, !val + U256::from(1u64))
105 }
106 }
107}
108
109impl From<I256> for U256 {
110 fn from(value: I256) -> U256 {
111 let sign = value.0;
112 if sign == Sign::Zero {
113 U256::ZERO
114 } else if sign == Sign::Plus {
115 value.1
116 } else {
117 !value.1 + U256::from(1u64)
118 }
119 }
120}
121
122impl Div for I256 {
123 type Output = I256;
124
125 fn div(self, other: I256) -> I256 {
126 if other == I256::zero() {
127 return I256::zero();
128 }
129
130 if self == I256::min_value() && other.1 == U256::from(1u64) {
131 return I256::min_value();
132 }
133
134 let d = (self.1 / other.1) & U256::SIGN_BIT_MASK;
135
136 if d == U256::ZERO {
137 return I256::zero();
138 }
139
140 match (self.0, other.0) {
141 (Sign::Zero, Sign::Plus)
142 | (Sign::Plus, Sign::Zero)
143 | (Sign::Zero, Sign::Zero)
144 | (Sign::Plus, Sign::Plus)
145 | (Sign::Minus, Sign::Minus) => I256(Sign::Plus, d),
146 (Sign::Zero, Sign::Minus)
147 | (Sign::Plus, Sign::Minus)
148 | (Sign::Minus, Sign::Zero)
149 | (Sign::Minus, Sign::Plus) => I256(Sign::Minus, d),
150 }
151 }
152}
153
154impl Rem for I256 {
155 type Output = I256;
156
157 fn rem(self, other: I256) -> I256 {
158 let r = (self.1 % other.1) & U256::SIGN_BIT_MASK;
159
160 if r == U256::ZERO {
161 return I256::zero();
162 }
163
164 I256(self.0, r)
165 }
166}
167
168#[cfg(test)]
169mod tests {
170 use std::num::Wrapping;
171
172 use super::*;
173
174 #[test]
175 fn div_i256() {
176 assert_eq!(Wrapping(i8::MIN) / Wrapping(-1), Wrapping(i8::MIN));
179
180 assert_eq!(100i8 / -1, -100i8);
181 assert_eq!(100i8 / 2, 50i8);
182
183 let one = I256(Sign::Zero, U256::from_usize(1));
185 let one_hundred = I256(Sign::Zero, U256::from_usize(100));
186 let fifty = I256(Sign::Plus, U256::from_usize(50));
187 let two = I256(Sign::Zero, U256::from_usize(2));
188 let neg_one_hundred = I256(Sign::Minus, U256::from_usize(100));
189 let minus_one = I256(Sign::Minus, U256::from_usize(1));
190 let max_value = I256(
191 Sign::Plus,
192 U256::from_usize(2).pow(U256::from_usize(255)) - U256::ONE,
193 );
194 let neg_max_value = I256(
195 Sign::Minus,
196 U256::from_usize(2).pow(U256::from_usize(255)) - U256::ONE,
197 );
198
199 assert_eq!(I256::min_value() / minus_one, I256::min_value());
200 assert_eq!(I256::min_value() / one, I256::min_value());
201 assert_eq!(max_value / one, max_value);
202 assert_eq!(max_value / minus_one, neg_max_value);
203
204 assert_eq!(one_hundred / minus_one, neg_one_hundred);
205 assert_eq!(one_hundred / two, fifty);
206 }
207}