bn_rs/bignumber/
from.rs

1use primitive_types::{H128, H160, H256, H512, U128, U256, U512};
2
3use super::{BigNumber, BigNumberError};
4
5macro_rules! try_from_primitive_uint {
6    ($type:ty) => {
7        impl TryFrom<BigNumber> for $type {
8            type Error = BigNumberError;
9
10            fn try_from(value: BigNumber) -> Result<$type, Self::Error> {
11                Ok(<$type>::from_str_radix(&value.hex(), 16)?)
12            }
13        }
14    };
15}
16
17macro_rules! try_from_primitive_hash {
18    ($type:ty) => {
19        impl TryFrom<BigNumber> for $type {
20            type Error = BigNumberError;
21
22            fn try_from(value: BigNumber) -> Result<$type, Self::Error> {
23                const BYTES_LENGTH: usize = std::mem::size_of::<$type>();
24
25                let raw_hex = value.hex();
26                let hex = raw_hex.strip_prefix("0x").unwrap_or(&raw_hex);
27
28                if hex.starts_with('-') {
29                    return Err(rustc_hex::FromHexError::InvalidHexCharacter('-', 0).into());
30                }
31
32                let bytes = (0..hex.len())
33                    .step_by(2)
34                    .map(|i| {
35                        u8::from_str_radix(&hex[i..i + 2], 16).map_err(|_| {
36                            rustc_hex::FromHexError::InvalidHexCharacter(
37                                hex.chars().nth(i).unwrap(),
38                                i,
39                            )
40                        })
41                    })
42                    .collect::<Result<Vec<_>, _>>()?;
43
44                if bytes.len() > BYTES_LENGTH {
45                    return Err(rustc_hex::FromHexError::InvalidHexLength.into());
46                }
47
48                let mut result = [0 as u8; BYTES_LENGTH];
49                let offset = BYTES_LENGTH - bytes.len();
50                for (i, byte) in bytes.into_iter().enumerate() {
51                    result[offset + i] = byte;
52                }
53
54                Ok(<$type>::from(result))
55            }
56        }
57    };
58}
59
60macro_rules! try_from_std {
61    ($type:ty) => {
62        impl TryFrom<BigNumber> for $type {
63            type Error = BigNumberError;
64
65            fn try_from(value: BigNumber) -> Result<$type, Self::Error> {
66                let hex = value.hex();
67
68                if hex.starts_with('-') {
69                    Ok(<$type>::from_str_radix(
70                        &[&hex[..1], &hex[3..]].concat(),
71                        16,
72                    )?)
73                } else {
74                    Ok(<$type>::from_str_radix(&hex[2..], 16)?)
75                }
76            }
77        }
78    };
79}
80
81try_from_primitive_uint!(U128);
82try_from_primitive_uint!(U256);
83try_from_primitive_uint!(U512);
84try_from_primitive_hash!(H128);
85try_from_primitive_hash!(H160);
86try_from_primitive_hash!(H256);
87try_from_primitive_hash!(H512);
88try_from_std!(isize);
89try_from_std!(i8);
90try_from_std!(i16);
91try_from_std!(i32);
92try_from_std!(i64);
93try_from_std!(i128);
94try_from_std!(usize);
95try_from_std!(u8);
96try_from_std!(u16);
97try_from_std!(u32);
98try_from_std!(u64);
99try_from_std!(u128);
100
101#[cfg(test)]
102mod tests {
103    use primitive_types::{H160, H256, H512, U128, U256, U512};
104    use wasm_bindgen_test::*;
105
106    use super::{BigNumber, BigNumberError};
107
108    #[wasm_bindgen_test]
109    fn primitive_uint() {
110        let bignumber = BigNumber::new(U256::MAX.to_string());
111        let middle_bignumber = BigNumber::new((U256::MAX - U256::from(U128::MAX)).to_string());
112
113        assert!(matches!(
114            U128::try_from(BigNumber::from(bignumber.clone())).err(),
115            Some(BigNumberError::PrimitiveUint(_))
116        ));
117        assert_eq!(
118            U256::try_from(BigNumber::from(bignumber.clone())).unwrap(),
119            U256::MAX
120        );
121        assert_eq!(
122            U256::try_from(middle_bignumber).unwrap(),
123            U256::MAX - U256::from(U128::MAX)
124        );
125        assert_eq!(U512::try_from(bignumber).unwrap(), U512::from(U256::MAX));
126    }
127
128    #[wasm_bindgen_test]
129    fn primitive_hash() {
130        let h256 = H256::from([u8::MAX; 32]);
131        let bignumber = BigNumber::new(format!("{:#x}", h256));
132        let middle_h256 = H256::from(
133            <[u8; 32]>::try_from([[0; 8], [u8::MAX; 8], [u8::MAX; 8], [0; 8]].concat()).unwrap(),
134        );
135        let middle_bignumber = BigNumber::new(format!("{:#x}", middle_h256));
136
137        assert!(matches!(
138            H160::try_from(BigNumber::from(bignumber.clone())).err(),
139            Some(BigNumberError::PrimitiveHash(_))
140        ));
141        assert_eq!(
142            H256::try_from(BigNumber::from(bignumber.clone())).unwrap(),
143            H256::from([u8::MAX; 32]),
144        );
145        assert_eq!(H256::try_from(middle_bignumber).unwrap(), middle_h256);
146        assert_eq!(
147            H512::try_from(bignumber).unwrap(),
148            H512::from(<[u8; 64]>::try_from([[0; 32], [u8::MAX; 32]].concat()).unwrap()),
149        );
150    }
151
152    #[wasm_bindgen_test]
153    fn std_uint() {
154        let bignumber = BigNumber::new(u64::MAX.to_string());
155        let middle_u64 = u64::MAX - u32::MAX as u64;
156        let middle_bignumber = BigNumber::new(middle_u64.to_string());
157
158        assert!(matches!(
159            u8::try_from(BigNumber::from(bignumber.clone())).err(),
160            Some(BigNumberError::Std(_))
161        ));
162        assert_eq!(u64::try_from(middle_bignumber).unwrap(), middle_u64);
163        assert_eq!(u128::try_from(bignumber).unwrap(), u64::MAX as u128);
164    }
165
166    #[wasm_bindgen_test]
167    fn std_int() {
168        let bignumber = BigNumber::new(i64::MIN.to_string());
169        let middle_i64 = i64::MIN - i32::MIN as i64;
170        let middle_bignumber = BigNumber::new(middle_i64.to_string());
171
172        assert!(matches!(
173            u8::try_from(BigNumber::from(bignumber.clone())).err(),
174            Some(BigNumberError::Std(_))
175        ));
176        assert_eq!(i64::try_from(middle_bignumber).unwrap(), middle_i64);
177        assert_eq!(i128::try_from(bignumber).unwrap(), i64::MIN as i128);
178    }
179}