use num_traits::cast::ToPrimitive; #[derive(Clone, Debug)] pub enum BigIntOrI64 { Int(i64), BigInt(num_bigint::BigInt), } impl PartialEq for BigIntOrI64 { fn eq(&self, other: &Self) -> bool { use BigIntOrI64::*; match (&self, &other) { (Int(i), Int(j)) => i == j, (Int(i), BigInt(b)) | (BigInt(b), Int(i)) => b == &num_bigint::BigInt::from(*i), (BigInt(a), BigInt(b)) => a == b, } } } impl Eq for BigIntOrI64 {} /// A value holding JavaScript /// [BigInt](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt) type #[derive(Clone, Debug, PartialEq, Eq)] pub struct BigInt { pub(crate) inner: BigIntOrI64, } impl BigInt { /// Return `Some` if value fits into `i64` and `None` otherwise pub fn as_i64(&self) -> Option { match &self.inner { BigIntOrI64::Int(int) => Some(*int), BigIntOrI64::BigInt(bigint) => bigint.to_i64(), } } /// Convert value into `num_bigint::BigInt` pub fn into_bigint(self) -> num_bigint::BigInt { match self.inner { BigIntOrI64::Int(int) => int.into(), BigIntOrI64::BigInt(bigint) => bigint, } } } impl std::fmt::Display for BigInt { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { match self.inner { BigIntOrI64::Int(i) => write!(f, "{i}"), BigIntOrI64::BigInt(ref i) => write!(f, "{i}"), } } } impl From for BigInt { fn from(int: i64) -> Self { BigInt { inner: BigIntOrI64::Int(int), } } } impl From for BigInt { fn from(bigint: num_bigint::BigInt) -> Self { BigInt { inner: BigIntOrI64::BigInt(bigint), } } } #[cfg(test)] mod tests { #[allow(unused_imports)] use super::*; #[test] fn test_bigint_as_i64() { let value = BigInt { inner: BigIntOrI64::Int(1234i64), }; assert_eq!(value.as_i64(), Some(1234i64)); } #[test] fn test_bigint_as_i64_overflow() { let value = BigInt { inner: BigIntOrI64::BigInt(num_bigint::BigInt::from(std::i128::MAX)), }; assert_eq!(value.as_i64(), None); } #[test] fn test_bigint_into_bigint() { for i in vec![ 0 as i128, std::i64::MAX as i128, std::i64::MIN as i128, std::i128::MAX, std::i128::MIN, ] { let value = BigInt { inner: BigIntOrI64::BigInt(num_bigint::BigInt::from(i)), }; assert_eq!(value.into_bigint(), num_bigint::BigInt::from(i)); } } }