1use js_sys::JsString;
2use primitive_types::{H128, H160, H256, H512, U128, U256, U512};
3
4use super::{BNError, BN};
5
6macro_rules! try_from {
7 ($type:ty, $byte_length:expr, $from_fn:ident) => {
8 impl TryFrom<BN> for $type {
9 type Error = BNError;
10
11 fn try_from(value: BN) -> Result<$type, Self::Error> {
12 if value.negative() == 1 {
14 return Err(BNError::NegativeUint);
15 }
16
17 if value.byte_length() > $byte_length {
18 return Err(BNError::Overflow(stringify!($type).into()));
19 }
20
21 let bytes = <[u8; $byte_length as usize]>::try_from(
23 &*value
24 .to_array("be".into(), $byte_length)
25 .map_err(|err| BNError::Throw(JsString::from(err).into()))?,
26 )
27 .unwrap();
28
29 Ok(<$type>::$from_fn(bytes))
30 }
31 }
32 };
33}
34
35macro_rules! try_from_primitive {
36 ($type:ty) => {
37 try_from!($type, std::mem::size_of::<$type>() as u32, from);
38 };
39}
40
41macro_rules! try_from_std {
42 ($type:ty) => {
43 try_from!($type, <$type>::BITS / 8, from_be_bytes);
44 };
45}
46
47try_from_primitive!(U128);
48try_from_primitive!(U256);
49try_from_primitive!(U512);
50try_from_primitive!(H128);
51try_from_primitive!(H160);
52try_from_primitive!(H256);
53try_from_primitive!(H512);
54try_from_std!(usize);
61try_from_std!(u8);
62try_from_std!(u16);
63try_from_std!(u32);
64try_from_std!(u64);
65try_from_std!(u128);
66
67#[cfg(test)]
68mod tests {
69 use primitive_types::{H160, H256, H512, U128, U256, U512};
70 use wasm_bindgen_test::*;
71
72 use super::{BNError, BN};
73
74 #[wasm_bindgen_test]
75 fn primitive_uint() {
76 let bn = BN::new(U256::MAX.to_string(), 10);
77 let middle_bn = BN::new((U256::MAX - U256::from(U128::MAX)).to_string(), 10);
78
79 assert!(matches!(
80 U128::try_from(BN::from(bn.clone())).err(),
81 Some(BNError::Overflow(_))
82 ));
83 assert_eq!(U256::try_from(BN::from(bn.clone())).unwrap(), U256::MAX);
84 assert_eq!(
85 U256::try_from(middle_bn).unwrap(),
86 U256::MAX - U256::from(U128::MAX)
87 );
88 assert_eq!(U512::try_from(bn).unwrap(), U512::from(U256::MAX));
89 }
90
91 #[wasm_bindgen_test]
92 fn primitive_hash() {
93 let h256 = H256::from([u8::MAX; 32]);
94 let bn = BN::new(format!("{:x}", h256), 16);
95 let middle_h256 = H256::from(
96 <[u8; 32]>::try_from([[0; 8], [u8::MAX; 8], [u8::MAX; 8], [0; 8]].concat()).unwrap(),
97 );
98 let middle_bn = BN::new(format!("{:x}", middle_h256), 16);
99
100 assert!(matches!(
101 H160::try_from(BN::from(bn.clone())).err(),
102 Some(BNError::Overflow(_))
103 ));
104 assert_eq!(
105 H256::try_from(BN::from(bn.clone())).unwrap(),
106 H256::from([u8::MAX; 32]),
107 );
108 assert_eq!(H256::try_from(middle_bn).unwrap(), middle_h256);
109 assert_eq!(
110 H512::try_from(bn).unwrap(),
111 H512::from(<[u8; 64]>::try_from([[0; 32], [u8::MAX; 32]].concat()).unwrap()),
112 );
113 }
114
115 #[wasm_bindgen_test]
130 fn std_uint() {
131 let bn = BN::new(u64::MAX.to_string(), 10);
132 let middle_u64 = u64::MAX - u32::MAX as u64;
133 let middle_bn = BN::new(middle_u64.to_string(), 10);
134
135 assert!(matches!(
136 u8::try_from(BN::from(bn.clone())).err(),
137 Some(BNError::Overflow(_))
138 ));
139 assert_eq!(u64::try_from(middle_bn).unwrap(), middle_u64);
140 assert_eq!(u128::try_from(bn).unwrap(), u64::MAX as u128);
141 }
142}