From f0050a21839cb8a20f6cd3480412e37b7ce37853 Mon Sep 17 00:00:00 2001 From: Zack Slayton Date: Mon, 3 Jul 2023 16:33:39 -0400 Subject: [PATCH] Added From and From impls for Decimal --- src/types/coefficient.rs | 6 +++--- src/types/decimal.rs | 43 ++++++++++++++++++++++++++++++++-------- 2 files changed, 38 insertions(+), 11 deletions(-) diff --git a/src/types/coefficient.rs b/src/types/coefficient.rs index 982eed0a..a78eba78 100644 --- a/src/types/coefficient.rs +++ b/src/types/coefficient.rs @@ -3,7 +3,7 @@ use num_traits::Zero; use crate::result::{IonError, IonFailure}; use crate::types::integer::UIntData; -use crate::types::UInt; +use crate::types::{Int, UInt}; use crate::IonResult; use std::convert::TryFrom; use std::fmt::{Display, Formatter}; @@ -169,7 +169,7 @@ macro_rules! impl_coefficient_from_unsigned_int_types { } )*) } -impl_coefficient_from_unsigned_int_types!(u8, u16, u32, u64, u128, usize, BigUint); +impl_coefficient_from_unsigned_int_types!(u8, u16, u32, u64, u128, usize, UInt, BigUint); // This macro makes it possible to turn signed integers into a Coefficient using `.into()`. macro_rules! impl_coefficient_from_signed_int_types { @@ -182,7 +182,7 @@ macro_rules! impl_coefficient_from_signed_int_types { } )*) } -impl_coefficient_from_signed_int_types!(i8, i16, i32, i64, i128, isize); +impl_coefficient_from_signed_int_types!(i8, i16, i32, i64, i128, isize, Int); // `BigInt` can't represent -0, so this is technically a lossy operation. impl TryFrom for BigInt { diff --git a/src/types/decimal.rs b/src/types/decimal.rs index 2208294a..9b36dd1a 100644 --- a/src/types/decimal.rs +++ b/src/types/decimal.rs @@ -7,7 +7,7 @@ use crate::ion_data::{IonEq, IonOrd}; use crate::result::{IonError, IonFailure}; use crate::types::integer::UIntData; use crate::types::{Coefficient, Sign, UInt}; -use crate::IonResult; +use crate::{Int, IonResult}; use num_integer::Integer; use num_traits::{ToPrimitive, Zero}; use std::convert::{TryFrom, TryInto}; @@ -311,11 +311,7 @@ macro_rules! impl_decimal_from_signed_primitive_integer { fn from(value: $t) -> Self { let sign = if value < 0 {Sign::Negative} else {Sign::Positive}; // Discard the sign and convert the value to a u64. - let magnitude: u64 = value.checked_abs() - .and_then(|v| Some(v.abs() as u64)) - // If .abs() fails, it's because <$t>::MIN.abs() cannot be represented - // as a $t. We can handle this case by simply using <$>::MAX + 1 - .unwrap_or_else(|| (<$t>::MAX as u64) + 1); + let magnitude: u64 = value.unsigned_abs() as u64; let coefficient = Coefficient::new(sign, magnitude); Decimal::new(coefficient, 0) } @@ -324,6 +320,18 @@ macro_rules! impl_decimal_from_signed_primitive_integer { } impl_decimal_from_signed_primitive_integer!(i8, i16, i32, i64, isize); +impl From for Decimal { + fn from(value: Int) -> Self { + Decimal::new(value, 0) + } +} + +impl From for Decimal { + fn from(value: UInt) -> Self { + Decimal::new(value, 0) + } +} + impl TryFrom for Decimal { type Error = IonError; @@ -485,9 +493,9 @@ impl TryFrom for BigDecimal { #[cfg(test)] mod decimal_tests { use crate::result::IonResult; - use crate::types::{Coefficient, Decimal, Sign, UInt}; + use crate::types::{Coefficient, Decimal, Int, Sign, UInt}; use bigdecimal::BigDecimal; - use num_bigint::BigUint; + use num_bigint::{BigInt, BigUint}; use num_traits::{Float, ToPrimitive}; use std::cmp::Ordering; @@ -789,4 +797,23 @@ mod decimal_tests { fn test_precision(#[case] value: Decimal, #[case] expected: u64) { assert_eq!(value.precision(), expected); } + + #[rstest] + #[case(0, Decimal::new(0, 0))] + #[case(1, Decimal::new(1, 0))] + #[case(-1, Decimal::new(-1, 0))] + #[case(-8675309i64, Decimal::new(-8675309i64, 0))] + #[case(8675309u32, Decimal::new(8675309u32, 0))] + // mixed coefficient representations + #[case(8675309i64, Decimal::new(8675309u32, 0))] + #[case(Int::from(-8675309i64), Decimal::new(-8675309i64, 0))] + #[case(Int::from(BigInt::from(-8675309i64)), Decimal::new(-8675309i64, 0))] + #[case(UInt::from(8675309u64), Decimal::new(8675309u64, 0))] + #[case(UInt::from(BigUint::from(8675309u64)), Decimal::new(8675309u64, 0))] + fn decimal_from_integers( + #[case] coefficient: impl Into, + #[case] expected: Decimal, + ) { + assert_eq!(Decimal::new(coefficient, 0), expected); + } }