cardano_serialization_lib/protocol_types/numeric/
big_int.rs

1use num_bigint::Sign;
2use num_integer::Integer;
3use num_traits::Signed;
4use crate::*;
5
6#[wasm_bindgen]
7#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd, Hash)]
8pub struct BigInt(pub(crate) num_bigint::BigInt);
9
10impl_to_from!(BigInt);
11
12impl serde::Serialize for BigInt {
13    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
14        where
15            S: serde::Serializer,
16    {
17        serializer.serialize_str(&self.to_str())
18    }
19}
20
21impl<'de> serde::de::Deserialize<'de> for BigInt {
22    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
23        where
24            D: serde::de::Deserializer<'de>,
25    {
26        let s = <String as serde::de::Deserialize>::deserialize(deserializer)?;
27        BigInt::from_str(&s).map_err(|_e| {
28            serde::de::Error::invalid_value(
29                serde::de::Unexpected::Str(&s),
30                &"string rep of a big int",
31            )
32        })
33    }
34}
35
36impl JsonSchema for BigInt {
37    fn schema_name() -> String {
38        String::from("BigInt")
39    }
40    fn json_schema(gen: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema {
41        String::json_schema(gen)
42    }
43    fn is_referenceable() -> bool {
44        String::is_referenceable()
45    }
46}
47
48#[wasm_bindgen]
49impl BigInt {
50    pub fn is_zero(&self) -> bool {
51        self.0.sign() == Sign::NoSign
52    }
53
54    pub fn as_u64(&self) -> Option<BigNum> {
55        let (sign, u64_digits) = self.0.to_u64_digits();
56        if sign == Sign::Minus {
57            return None;
58        }
59        match u64_digits.len() {
60            0 => Some(BigNum::zero()),
61            1 => Some((*u64_digits.first().unwrap()).into()),
62            _ => None,
63        }
64    }
65
66    pub fn as_int(&self) -> Option<Int> {
67        let (sign, u64_digits) = self.0.to_u64_digits();
68        let u64_digit = match u64_digits.len() {
69            0 => Some(BigNum::zero()),
70            1 => Some((*u64_digits.first().unwrap()).into()),
71            _ => None,
72        }?;
73        match sign {
74            num_bigint::Sign::NoSign | num_bigint::Sign::Plus => Some(Int::new(&u64_digit)),
75            num_bigint::Sign::Minus => Some(Int::new_negative(&u64_digit)),
76        }
77    }
78
79    pub fn from_str(text: &str) -> Result<BigInt, JsError> {
80        use std::str::FromStr;
81        num_bigint::BigInt::from_str(text)
82            .map_err(|e| JsError::from_str(&format! {"{:?}", e}))
83            .map(Self)
84    }
85
86    pub fn to_str(&self) -> String {
87        self.0.to_string()
88    }
89
90    pub fn add(&self, other: &BigInt) -> BigInt {
91        Self(&self.0 + &other.0)
92    }
93
94    pub fn sub(&self, other: &BigInt) -> BigInt {
95        Self(&self.0 - &other.0)
96    }
97
98    pub fn mul(&self, other: &BigInt) -> BigInt {
99        Self(&self.0 * &other.0)
100    }
101
102    pub fn pow(&self, exp: u32) -> BigInt {
103        Self(self.0.pow(exp))
104    }
105
106    pub fn one() -> BigInt {
107        Self(num_bigint::BigInt::from(1))
108    }
109
110    pub fn zero() -> BigInt {
111        Self(num_bigint::BigInt::from(0))
112    }
113
114    pub fn abs(&self) -> BigInt {
115        Self(self.0.abs())
116    }
117
118    pub fn increment(&self) -> BigInt {
119        self.add(&Self::one())
120    }
121
122    pub fn div_ceil(&self, other: &BigInt) -> BigInt {
123        Self(self.0.div_ceil(&other.0))
124    }
125
126    pub fn div_floor(&self, other: &BigInt) -> BigInt {
127        Self(self.0.div_floor(&other.0))
128    }
129
130    pub(crate) fn is_negative(&self) -> bool {
131        self.0.is_negative()
132    }
133}
134
135impl<T> std::convert::From<T> for BigInt
136    where
137        T: std::convert::Into<num_bigint::BigInt>,
138{
139    fn from(x: T) -> Self {
140        Self(x.into())
141    }
142}
143
144impl From<BigNum> for BigInt {
145    fn from(x: BigNum) -> Self {
146        Self(x.0.into())
147    }
148}
149
150impl From<&BigNum> for BigInt {
151    fn from(x: &BigNum) -> Self {
152        Self(x.0.into())
153    }
154}
155
156pub fn to_bigint(val: u64) -> BigInt {
157    BigInt::from_str(&val.to_string()).unwrap()
158}