Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds From<Int> and From<UInt>` impls for Decimal #592

Merged
merged 1 commit into from
Jul 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 3 additions & 3 deletions src/types/coefficient.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -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 {
Expand All @@ -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<Coefficient> for BigInt {
Expand Down
43 changes: 35 additions & 8 deletions src/types/decimal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -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)
}
Expand All @@ -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<Int> for Decimal {
fn from(value: Int) -> Self {
Decimal::new(value, 0)
}
}

impl From<UInt> for Decimal {
fn from(value: UInt) -> Self {
Decimal::new(value, 0)
}
}

impl TryFrom<f32> for Decimal {
type Error = IonError;

Expand Down Expand Up @@ -485,9 +493,9 @@ impl TryFrom<Decimal> 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;
Expand Down Expand Up @@ -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<Coefficient>,
#[case] expected: Decimal,
) {
assert_eq!(Decimal::new(coefficient, 0), expected);
}
}