Skip to content

Commit d4932bc

Browse files
committed
Added TryFrom<f64>
1 parent 8b182aa commit d4932bc

1 file changed

Lines changed: 69 additions & 0 deletions

File tree

src/lib.rs

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -466,6 +466,9 @@ macro_rules! impl_from_int {
466466
$(
467467
impl From<$t> for Decimal {
468468
fn from(val: $t) -> Self {
469+
// Integer conversion is infallible - always produces valid decimal bytes.
470+
// Uses string conversion internally since the byte encoding is designed
471+
// around decimal string parsing (BCD encoding of digit pairs).
469472
Decimal::from_str(&val.to_string()).expect("Integer is always valid")
470473
}
471474
}
@@ -475,6 +478,49 @@ macro_rules! impl_from_int {
475478

476479
impl_from_int!(i8, i16, i32, i64, i128, u8, u16, u32, u64, u128);
477480

481+
impl TryFrom<f64> for Decimal {
482+
type Error = DecimalError;
483+
484+
/// Converts an f64 to a Decimal.
485+
///
486+
/// Special values are handled:
487+
/// - `f64::NAN` → `Decimal::nan()`
488+
/// - `f64::INFINITY` → `Decimal::infinity()`
489+
/// - `f64::NEG_INFINITY` → `Decimal::neg_infinity()`
490+
///
491+
/// Note: Due to f64's limited precision (~15-17 significant digits),
492+
/// very precise decimal values may lose precision when converted from f64.
493+
/// For exact decimal representation, use `Decimal::from_str()` instead.
494+
///
495+
/// # Example
496+
///
497+
/// ```
498+
/// use decimal_bytes::Decimal;
499+
///
500+
/// let d: Decimal = 123.456f64.try_into().unwrap();
501+
/// assert_eq!(d.to_string(), "123.456");
502+
///
503+
/// let inf: Decimal = f64::INFINITY.try_into().unwrap();
504+
/// assert!(inf.is_pos_infinity());
505+
///
506+
/// let nan: Decimal = f64::NAN.try_into().unwrap();
507+
/// assert!(nan.is_nan());
508+
/// ```
509+
fn try_from(val: f64) -> Result<Self, Self::Error> {
510+
if val.is_nan() {
511+
return Ok(Decimal::nan());
512+
}
513+
if val.is_infinite() {
514+
return Ok(if val.is_sign_positive() {
515+
Decimal::infinity()
516+
} else {
517+
Decimal::neg_infinity()
518+
});
519+
}
520+
Decimal::from_str(&val.to_string())
521+
}
522+
}
523+
478524
impl Default for Decimal {
479525
fn default() -> Self {
480526
Decimal {
@@ -705,6 +751,29 @@ mod tests {
705751
assert_eq!(d.to_string(), "-100");
706752
}
707753

754+
#[test]
755+
fn test_from_f64() {
756+
// Normal f64 values
757+
let d: Decimal = 123.456f64.try_into().unwrap();
758+
assert_eq!(d.to_string(), "123.456");
759+
760+
let d: Decimal = (-99.5f64).try_into().unwrap();
761+
assert_eq!(d.to_string(), "-99.5");
762+
763+
let d: Decimal = 0.0f64.try_into().unwrap();
764+
assert!(d.is_zero());
765+
766+
// Special values
767+
let inf: Decimal = f64::INFINITY.try_into().unwrap();
768+
assert!(inf.is_pos_infinity());
769+
770+
let neg_inf: Decimal = f64::NEG_INFINITY.try_into().unwrap();
771+
assert!(neg_inf.is_neg_infinity());
772+
773+
let nan: Decimal = f64::NAN.try_into().unwrap();
774+
assert!(nan.is_nan());
775+
}
776+
708777
#[test]
709778
fn test_serialization() {
710779
let d = Decimal::from_str("123.456").unwrap();

0 commit comments

Comments
 (0)