af_utilities/types/
i256.rs1use std::cmp::Ordering;
2use std::ops::{
3 Add,
4 AddAssign,
5 Div,
6 DivAssign,
7 Mul,
8 MulAssign,
9 Neg,
10 Rem,
11 RemAssign,
12 Sub,
13 SubAssign,
14};
15
16use af_sui_types::u256::U256;
17use num_traits::{One, Zero};
18use serde::{Deserialize, Serialize};
19
20use super::errors::Error;
21use super::onchain;
22
23#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Deserialize, Serialize)]
24pub struct I256(U256);
25
26impl std::fmt::Display for I256 {
27 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
28 if self.is_neg() {
29 write!(f, "-{}", self.uabs())
30 } else {
31 write!(f, "{}", self.0)
32 }
33 }
34}
35
36macro_rules! impl_from_uint {
37 ($($int:ty)*) => {
38 $(
39 impl From<$int> for I256 {
40 fn from(value: $int) -> Self {
41 Self(U256::from(value))
42 }
43 }
44 )*
45 };
46}
47
48impl_from_uint!(u8 u16 u32 u64 u128);
49
50macro_rules! impl_from_int {
51 ($($int:ty)*) => {
52 $(
53 impl From<$int> for I256 {
54 fn from(value: $int) -> Self {
55 let is_neg = value.is_negative();
56 let abs = Self::from(value.unsigned_abs());
57 match is_neg {
58 true => abs.neg(),
59 false => abs,
60 }
61 }
62 }
63 )*
64 };
65}
66
67impl_from_int!(i8 i16 i32 i64 i128);
68
69macro_rules! impl_try_into_int {
70 ($($bridge:ty => $int:ty),*) => {
71 $(
72 impl TryFrom<I256> for $int {
73 type Error = Error;
74
75 fn try_from(value: I256) -> Result<Self, Self::Error> {
76 let is_neg = value.is_neg();
77 let bridge: $bridge = value.uabs().try_into().map_err(|_| Error::Overflow)?;
78 let self_: Self = bridge.try_into().map_err(|_| Error::Overflow)?;
79 Ok(match is_neg {
80 true => -self_,
81 false => self_,
82 })
83 }
84 }
85 )*
86 };
87}
88
89impl_try_into_int!(u8 => i8, u16 => i16, u32 => i32, u64 => i64, u128 => i128);
90
91macro_rules! impl_try_into_uint {
92 ($($int:ty)*) => {
93 $(
94 impl TryFrom<I256> for $int {
95 type Error = Error;
96
97 fn try_from(value: I256) -> Result<Self, Self::Error> {
98 if value.is_neg() {
99 return Err(Error::Underflow);
100 }
101 value.uabs().try_into().map_err(|_| Error::Overflow)
102 }
103 }
104 )*
105 };
106}
107
108impl_try_into_uint!(u8 u16 u32 u64 u128);
109
110impl TryFrom<U256> for I256 {
111 type Error = Error;
112
113 fn try_from(value: U256) -> Result<Self, Self::Error> {
114 if value <= onchain::max_i256() {
115 Ok(Self(value))
116 } else {
117 Err(Error::Overflow)
118 }
119 }
120}
121
122impl TryFrom<I256> for U256 {
123 type Error = Error;
124
125 fn try_from(value: I256) -> Result<Self, Self::Error> {
126 if value.is_neg() {
127 return Err(Error::Underflow);
128 }
129 Ok(value.0)
130 }
131}
132
133impl Add for I256 {
134 type Output = Self;
135
136 fn add(self, rhs: Self) -> Self::Output {
137 let Self(x) = self;
138 let Self(y) = rhs;
139 let greatest_bit = Self::greatest_bit();
140 let not_greatest_bit = Self::not_greatest_bit();
141
142 let w = (x & not_greatest_bit) + (y & not_greatest_bit);
144 Self(if x ^ y < greatest_bit {
145 w
149 } else {
150 w ^ greatest_bit
153 })
154 }
155}
156
157impl Sub for I256 {
158 type Output = Self;
159
160 fn sub(self, rhs: Self) -> Self::Output {
161 let Self(x) = self;
162 let Self(y) = rhs;
163 let w = if x >= y {
165 x - y
166 } else {
167 ((y - x) ^ Self::neg_one().0) + U256::one()
168 };
169 Self(w)
171 }
172}
173
174impl Mul for I256 {
175 type Output = Self;
176
177 fn mul(self, rhs: Self) -> Self::Output {
178 let z = self.uabs() * rhs.uabs();
179 let (Self(x), Self(y)) = (self, rhs);
180 let greatest_bit = Self::greatest_bit();
181
182 Self(if x ^ y < greatest_bit {
183 z
185 } else {
186 (greatest_bit - z) ^ greatest_bit
188 })
189 }
190}
191
192impl Div for I256 {
193 type Output = Self;
194
195 fn div(self, rhs: Self) -> Self::Output {
196 let z = self.uabs() / rhs.uabs();
197 let (Self(x), Self(y)) = (self, rhs);
198 let greatest_bit = Self::greatest_bit();
199
200 Self(if x ^ y < greatest_bit {
201 z
203 } else {
204 (greatest_bit - z) ^ greatest_bit
205 })
206 }
207}
208
209impl Rem for I256 {
210 type Output = Self;
211
212 fn rem(self, rhs: Self) -> Self::Output {
213 let is_neg = self.is_neg();
214 let abs_rem = Self(self.uabs() % rhs.uabs());
215 match is_neg {
216 true => abs_rem.neg(),
217 false => abs_rem,
218 }
219 }
220}
221
222super::reuse_op_for_assign!(I256 {
223 AddAssign add_assign +,
224 SubAssign sub_assign -,
225 MulAssign mul_assign *,
226 DivAssign div_assign /,
227 RemAssign rem_assign %,
228});
229
230impl PartialOrd for I256 {
231 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
232 Some(self.cmp(other))
233 }
234}
235
236impl Ord for I256 {
237 fn cmp(&self, other: &Self) -> Ordering {
238 let Self(x) = self;
239 let Self(y) = other;
240
241 if x == y {
242 Ordering::Equal
243 } else if *x ^ Self::greatest_bit() < *y ^ Self::greatest_bit() {
244 Ordering::Less
245 } else {
246 Ordering::Greater
247 }
248 }
249}
250
251impl Neg for I256 {
252 type Output = Self;
253
254 fn neg(self) -> Self::Output {
255 Self(((self.0 ^ Self::not_greatest_bit()) + U256::one()) ^ Self::greatest_bit())
256 }
257}
258
259impl One for I256 {
260 fn one() -> Self {
261 Self::one()
262 }
263}
264
265impl Zero for I256 {
266 fn zero() -> Self {
267 Self(U256::zero())
268 }
269
270 fn is_zero(&self) -> bool {
271 self.0 == U256::zero()
272 }
273}
274
275impl I256 {
276 fn greatest_bit() -> U256 {
277 U256::one() << 255_u8
278 }
279
280 fn not_greatest_bit() -> U256 {
281 (U256::one() << 255_u8) - U256::one()
282 }
283
284 pub const fn neg_one() -> Self {
285 Self(U256::max_value())
286 }
287
288 pub const fn into_inner(self) -> U256 {
289 self.0
290 }
291
292 pub const fn from_inner(inner: U256) -> Self {
293 Self(inner)
294 }
295
296 pub const fn one() -> Self {
297 Self(U256::one())
298 }
299
300 pub const fn zero() -> Self {
301 Self(U256::zero())
302 }
303
304 pub fn is_neg(&self) -> bool {
305 self.0 >= Self::greatest_bit()
306 }
307
308 pub fn uabs(&self) -> U256 {
311 let Self(x) = self;
312 if *x >= Self::greatest_bit() {
313 (*x ^ Self::neg_one().0) + U256::one()
314 } else {
315 *x
316 }
317 }
318
319 pub fn abs(self) -> Self {
320 let Self(x) = self;
321 let greatest_bit = Self::greatest_bit();
322 let not_greatest_bit = Self::not_greatest_bit();
323 Self(if x >= greatest_bit {
324 ((x ^ not_greatest_bit) + U256::one()) ^ greatest_bit
325 } else {
326 x
327 })
328 }
329}
330
331#[cfg(test)]
332#[allow(clippy::unwrap_used)]
333mod tests {
334 use super::*;
335
336 #[test]
337 fn from_u128_max_doesnt_overflow() {
338 assert!(!I256::from(u128::MAX).is_neg())
339 }
340
341 #[test]
342 fn from_i128_min_doesnt_underflow() {
343 assert!(I256::from(i128::MIN).is_neg())
344 }
345}