1use crate::ftas;
2#[cfg(feature = "wasm")]
3use alloc::{boxed::Box, string::ToString};
4use alloc::{format, vec, vec::Vec};
5use core::fmt;
6use ibig::UBig;
7use iris_ztd_derive::*;
8use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
9
10#[derive(NounEncode, NounDecode, Hashable, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
14#[wasm_noun_codec]
15#[cfg_attr(feature = "wasm", tsify(type = "string & { __tag_bignum: undefined }"))]
16pub struct Bignum {
17 tag: ftas!("bn"),
18 vals: Vec<u32>,
19}
20
21impl From<Vec<u32>> for Bignum {
22 fn from(vals: Vec<u32>) -> Self {
23 Bignum {
24 tag: Default::default(),
25 vals,
26 }
27 }
28}
29
30impl From<&UBig> for Bignum {
31 fn from(ibig: &UBig) -> Self {
32 let bytes = ibig.to_le_bytes();
33 let mut vals = vec![];
34 for b in bytes.chunks(4) {
35 let mut val = [0u8; 4];
36 val[..b.len()].copy_from_slice(b);
37 vals.push(u32::from_le_bytes(val));
38 }
39 Bignum {
40 tag: Default::default(),
41 vals,
42 }
43 }
44}
45
46impl From<&Bignum> for UBig {
47 fn from(bignum: &Bignum) -> Self {
48 let bytes = unsafe { bignum.vals.align_to::<u8>().1 };
49 ibig::UBig::from_le_bytes(bytes)
50 }
51}
52
53impl Serialize for Bignum {
54 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
55 where
56 S: Serializer,
57 {
58 serializer.serialize_str(&format!("{:x}", UBig::from(self)))
59 }
60}
61
62impl<'de> Deserialize<'de> for Bignum {
63 fn deserialize<D>(de: D) -> Result<Self, D::Error>
64 where
65 D: Deserializer<'de>,
66 {
67 struct BnVisitor;
68 impl<'de> de::Visitor<'de> for BnVisitor {
69 type Value = Bignum;
70
71 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
72 write!(formatter, "a hex string representing the big integer")
73 }
74
75 fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
76 where
77 E: de::Error,
78 {
79 let bigint = ibig::UBig::from_str_radix(s, 16)
80 .map_err(|_| de::Error::custom("not hex string"))?;
81 Ok(Bignum::from(&bigint))
82 }
83 }
84
85 de.deserialize_str(BnVisitor)
86 }
87}
88
89#[cfg(test)]
90mod tests {
91 use super::*;
92
93 #[test]
94 fn test_bignum() {
95 let bignum = Bignum::from(&UBig::from(12345678901234567890u128));
96 assert_eq!(UBig::from(&bignum), UBig::from(12345678901234567890u128));
97 let json = serde_json::to_string(&bignum).unwrap();
98 assert_eq!(json, "\"ab54a98ceb1f0ad2\"");
99 let bignum2 = serde_json::from_str(&json).unwrap();
100 assert_eq!(bignum, bignum2);
101 }
102
103 #[test]
104 fn test_bignum_p3() {
105 let bignum = Bignum::from(vec![1, 4294967293, 5, 4294967289, 5, 4294967293]);
106 let json = serde_json::to_string(&bignum).unwrap();
107 assert_eq!(json, "\"fffffffd00000005fffffff900000005fffffffd00000001\"");
108 let bignum2 = serde_json::from_str(&json).unwrap();
109 assert_eq!(bignum, bignum2);
110 }
111}