quick-js-datepatch/src/value/bigint.rs
2023-02-05 18:22:56 +01:00

107 lines
2.7 KiB
Rust

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<i64> {
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<i64> for BigInt {
fn from(int: i64) -> Self {
BigInt {
inner: BigIntOrI64::Int(int),
}
}
}
impl From<num_bigint::BigInt> 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));
}
}
}