1use std::{
2 fmt::Display,
3 ops::{Add, Mul, Sub},
4};
5
6use hex::FromHexError;
7use num::{bigint::ToBigInt, BigInt, FromPrimitive, Signed, ToPrimitive};
8use serde::{de, Deserialize, Serialize};
9
10use crate::{BytesVisitor, FromEtherHex, ToEtherHex};
11
12use concat_idents::concat_idents;
13
14use thiserror::Error;
15
16#[derive(Debug, Error)]
17pub enum SignedError {
18 #[error("OutOfRange: {0}")]
19 OutOfRange(String),
20
21 #[error("ToBigUnit: {0}")]
22 ToBigUnit(String),
23 #[error("FromHex: {0}")]
24 FromHex(#[from] FromHexError),
25}
26
27#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
29pub struct Int<const BITS: usize>(pub [u8; 32]);
30
31fn to_bytes32(value: BigInt, bits: usize) -> Result<[u8; 32], SignedError> {
32 if value.bits() as usize > bits {
33 return Err(SignedError::OutOfRange(format!(
34 "{} convert to uint<{}> failed",
35 value, bits
36 )));
37 }
38
39 let bytes = value.to_signed_bytes_be();
40
41 let mut buff = if value.is_negative() {
42 [0xffu8; 32]
43 } else {
44 [0u8; 32]
45 };
46
47 buff[(32 - bytes.len())..].copy_from_slice(&bytes);
48
49 Ok(buff)
50}
51
52impl<const BITS: usize> Int<BITS> {
53 pub fn new<N: ToBigInt + Signed>(value: N) -> Result<Self, SignedError> {
56 if let Some(value) = value.to_bigint() {
57 to_bytes32(value, BITS).map(|c| Self(c))
58 } else {
59 Err(SignedError::ToBigUnit(
60 "convert input into BigUnit failed".to_owned(),
61 ))
62 }
63 }
64}
65
66impl<const BITS: usize> Display for Int<BITS> {
67 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
68 let lead_ones = self.0.iter().take_while(|c| **c == 0xff).count();
69 let lead_zeros = self.0.iter().take_while(|c| **c == 0x00).count();
70
71 if lead_ones > 0 {
72 write!(f, "{}", (&self.0[(lead_ones - 1)..]).to_eth_value_hex())
73 } else {
74 write!(f, "{}", (&self.0[lead_zeros..]).to_eth_value_hex())
75 }
76 }
77}
78
79impl<const BITS: usize> TryFrom<&str> for Int<BITS> {
80 type Error = SignedError;
81 fn try_from(v: &str) -> Result<Self, Self::Error> {
82 let value = Vec::<u8>::from_eth_hex(v)?;
83
84 let lead_ones = value.iter().take_while(|c| **c == 0xff).count();
85
86 if value.len() - lead_ones + 1 > BITS / 8 {
87 return Err(SignedError::OutOfRange(format!(
88 "{} convert to int<{}> failed",
89 v, BITS
90 )));
91 }
92
93 let mut buff = if lead_ones > 0 {
94 [0xffu8; 32]
95 } else {
96 [0x0u8; 32]
97 };
98
99 buff[(32 - (value.len() - lead_ones))..].copy_from_slice(&value[lead_ones..]);
100
101 Ok(Int(buff))
102 }
103}
104
105impl<const BITS: usize> From<Int<BITS>> for BigInt {
106 fn from(value: Int<BITS>) -> Self {
107 BigInt::from(&value)
108 }
109}
110
111impl<const BITS: usize> From<&Int<BITS>> for BigInt {
112 fn from(value: &Int<BITS>) -> Self {
113 BigInt::from_signed_bytes_be(&value.0[(32 - BITS / 8)..])
114 }
115}
116
117impl<const BITS: usize> PartialOrd for Int<BITS> {
118 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
119 BigInt::from(self).partial_cmp(&BigInt::from(other))
120 }
121}
122
123impl<const BITS: usize> Sub for Int<BITS> {
124 type Output = Int<BITS>;
125
126 fn sub(self, rhs: Self) -> Self::Output {
127 Self::new(BigInt::from(self) - BigInt::from(rhs)).unwrap()
129 }
130}
131
132impl<const BITS: usize, N> Sub<N> for Int<BITS>
133where
134 N: ToBigInt,
135{
136 type Output = Int<BITS>;
137
138 fn sub(self, rhs: N) -> Self::Output {
139 Self::new(BigInt::from(self) - rhs.to_bigint().unwrap()).unwrap()
141 }
142}
143
144impl<const BITS: usize> Mul for Int<BITS> {
145 type Output = Int<BITS>;
146
147 fn mul(self, rhs: Self) -> Self::Output {
148 Self::new(BigInt::from(self) + BigInt::from(rhs)).unwrap()
149 }
150}
151
152impl<const BITS: usize, N> Mul<N> for Int<BITS>
153where
154 N: ToBigInt,
155{
156 type Output = Int<BITS>;
157
158 fn mul(self, rhs: N) -> Self::Output {
159 Self::new(BigInt::from(self) * rhs.to_bigint().unwrap()).unwrap()
160 }
161}
162
163impl<const BITS: usize> Add for Int<BITS> {
164 type Output = Int<BITS>;
165
166 fn add(self, rhs: Self) -> Self::Output {
167 Self::new(BigInt::from(self) + BigInt::from(rhs)).unwrap()
168 }
169}
170
171impl<const BITS: usize, N> Add<N> for Int<BITS>
172where
173 N: ToBigInt,
174{
175 type Output = Int<BITS>;
176
177 fn add(self, rhs: N) -> Self::Output {
178 Self::new(BigInt::from(self) + rhs.to_bigint().unwrap()).unwrap()
179 }
180}
181
182impl<const BITS: usize> Serialize for Int<BITS> {
183 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
184 where
185 S: serde::Serializer,
186 {
187 if serializer.is_human_readable() {
188 serializer.serialize_str(&self.to_string())
189 } else {
190 let name = format!("int{}", BITS);
192
193 let static_name = unsafe { &*(&name as *const String) };
194
195 serializer.serialize_newtype_struct(&static_name, &self.0)
196 }
197 }
198}
199
200struct IntVisitor<const BITS: usize>;
201
202impl<'de, const BITS: usize> de::Visitor<'de> for IntVisitor<BITS> {
203 type Value = Int<BITS>;
204 fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
205 write!(formatter, "expect string/number")
206 }
207
208 fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
209 where
210 E: de::Error,
211 {
212 Int::<BITS>::try_from(v).map_err(de::Error::custom)
213 }
214
215 fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E>
216 where
217 E: de::Error,
218 {
219 self.visit_u128(v as u128)
220 }
221
222 fn visit_u128<E>(self, v: u128) -> Result<Self::Value, E>
223 where
224 E: de::Error,
225 {
226 let value = BigInt::from_u128(v)
227 .ok_or(SignedError::ToBigUnit(format!(
228 "convert {} to BigInt failed",
229 v
230 )))
231 .map_err(de::Error::custom)?;
232
233 if value.bits() as usize > BITS {
234 return Err(SignedError::OutOfRange(format!(
235 "{} convert to uint<{}> failed",
236 value, BITS
237 )))
238 .map_err(de::Error::custom);
239 }
240
241 let value = to_bytes32(value, BITS).map_err(de::Error::custom)?;
242
243 Ok(Int(value))
244 }
245}
246
247impl<'de, const BITS: usize> Deserialize<'de> for Int<BITS> {
248 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
249 where
250 D: serde::Deserializer<'de>,
251 {
252 if deserializer.is_human_readable() {
253 deserializer.deserialize_any(IntVisitor)
254 } else {
255 let name = format!("int{}", BITS);
257
258 let static_name = unsafe { &*(&name as *const String) };
259
260 let value = deserializer
261 .deserialize_newtype_struct(static_name.as_str(), BytesVisitor::default())?;
262
263 let lead_ones = value.iter().take_while(|c| **c == 0xff).count();
264
265 if value.len() - lead_ones + 1 > BITS / 8 {
266 return Err(SignedError::OutOfRange(format!(
267 "{} convert to uint<{}> failed",
268 value.to_eth_hex(),
269 BITS
270 )))
271 .map_err(de::Error::custom);
272 }
273
274 let mut buff = if lead_ones > 0 {
275 [0xffu8; 32]
276 } else {
277 [0x0u8; 32]
278 };
279
280 buff[(32 - (value.len() - lead_ones))..].copy_from_slice(&value[lead_ones..]);
281
282 Ok(Int(buff))
283 }
284 }
285}
286
287macro_rules! convert_builtin_signed {
289 ($t: ident,$expr: tt,$($tails:tt),+) => {
290 impl<const BITS: usize> From<$expr> for $t<BITS> {
291 fn from(value: $expr) -> Self {
292 let value: BigInt = value.to_bigint().expect("usize to bigint");
293 Int::new(value).expect("Overflow")
295 }
296 }
297
298 concat_idents!(to_fn=to_,$expr {
299 impl<const BITS: usize> From<$t<BITS>> for Option<$expr> {
300 fn from(value: $t<BITS>) -> Self {
301 BigInt::from(value).to_fn()
302 }
303 }
304 });
305
306
307
308 convert_builtin_signed!($t,$($tails),*);
309 };
310 ($t: ident, $expr: tt) => {
311 impl<const BITS: usize> From<$expr> for $t<BITS> {
312 fn from(value: $expr) -> Self {
313 let value: BigInt = value.to_bigint().expect("usize to biguint");
314 Int::new(value).expect("Overflow")
316 }
317 }
318
319 concat_idents!(to_fn=to_,$expr {
320 impl<const BITS: usize> From<$t<BITS>> for Option<$expr> {
321 fn from(value: $t<BITS>) -> Self {
322 BigInt::from(value).to_fn()
323 }
324 }
325 });
326 };
327}
328
329convert_builtin_signed!(Int, isize, i128, i64, i32, i16, i8);
330
331pub type I256 = Int<256>;
332pub type I64 = Int<64>;
333
334#[cfg(test)]
335mod tests {
336 use serde_ethabi::{from_abi, to_abi};
337 use serde_ethrlp::rlp_encode;
338
339 use crate::ToEtherHex;
340
341 use super::*;
342
343 #[test]
344 fn test_arith() {
345 if let Some(value) = Option::<i8>::from(I256::new(-1i8).unwrap()) {
346 assert_eq!(value, -1i8);
347 }
348
349 if let Some(value) = Option::<i8>::from(I256::new(-4i8).unwrap()) {
350 assert_eq!(value, -4i8);
351 }
352
353 let lhs = Int::<8>::new(-1i8).unwrap();
354 let rhs = Int::<8>::new(-4i8).unwrap();
355
356 assert_eq!(lhs > rhs, true);
357
358 assert_eq!((rhs - lhs), Int::<8>::new(-3i8).unwrap());
359
360 assert_eq!(
361 BigInt::from(I256::new(-4isize).unwrap()),
362 BigInt::from_i8(-4).unwrap()
363 );
364 }
365
366 #[test]
367 fn test_rlp() {
368 _ = pretty_env_logger::try_init();
369
370 assert_eq!(
371 rlp_encode(&I256::from(0isize)).unwrap(),
372 rlp_encode(&0usize).unwrap()
373 );
374
375 assert_eq!(
376 rlp_encode(&I256::from(100000isize)).unwrap(),
377 rlp_encode(&100000isize).unwrap()
378 );
379 }
380
381 #[test]
382 fn test_abi() {
383 fn check<const BITS: usize>(value: Int<BITS>, expect: &str) {
384 assert_eq!(to_abi(&value).unwrap().to_eth_hex(), expect);
385
386 let buff = Vec::<u8>::from_eth_hex(expect).unwrap();
387
388 let expect: Int<BITS> = from_abi(buff).unwrap();
389
390 assert_eq!(value, expect);
391 }
392
393 check(
394 I256::from(-69isize),
395 "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbb",
396 );
397
398 check(
399 I256::from(-1isize),
400 "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
401 );
402 }
403}