Skip to main content

const_decimal/
conversion.rs

1use crate::{Decimal, Int64_9, Int128_18, ScaledInteger, Uint64_9, Uint128_18};
2
3// TODO: Implement From generically where the result cannot overflow.
4// TODO: Implement TryFrom generically where the result can overflow.
5
6impl From<Uint64_9> for Uint128_18 {
7    fn from(value: Uint64_9) -> Self {
8        // We know this multiplication can never overflow.
9        #[allow(clippy::arithmetic_side_effects)]
10        Decimal((u128::from(value.0)) * 10u128.pow(9))
11    }
12}
13
14impl From<Int64_9> for Int128_18 {
15    fn from(value: Int64_9) -> Self {
16        // We know this multiplication can never overflow.
17        #[allow(clippy::arithmetic_side_effects)]
18        Decimal((i128::from(value.0)) * 10i128.pow(9))
19    }
20}
21
22impl<I, const D: u8> Decimal<I, D>
23where
24    I: ScaledInteger<D>,
25{
26    // SAFETY: `num_traits::to_f64` does not panic on primitive types.
27    #[allow(clippy::missing_panics_doc)]
28    pub fn to_f64(&self) -> f64 {
29        self.0.to_f64().unwrap() / I::SCALING_FACTOR.to_f64().unwrap()
30    }
31
32    #[allow(clippy::missing_panics_doc)]
33    pub fn to_f32(&self) -> f32 {
34        self.0.to_f32().unwrap() / I::SCALING_FACTOR.to_f32().unwrap()
35    }
36}
37
38#[allow(clippy::float_cmp)]
39#[cfg(test)]
40mod tests {
41    use std::str::FromStr;
42
43    use proptest::prelude::Arbitrary;
44    use proptest::proptest;
45    use proptest::test_runner::TestRunner;
46
47    use super::*;
48    use crate::macros::generate_tests_for_common_variants;
49
50    #[test]
51    fn uint128_18_from_uint64_9() {
52        let mut runner = TestRunner::default();
53        let input = Decimal::arbitrary();
54
55        runner
56            .run(&input, |decimal: Decimal<u64, 9>| {
57                let out = Uint128_18::from(decimal);
58                let out_f = f64::from_str(&out.to_string()).unwrap();
59                let decimal_f = f64::from_str(&decimal.to_string()).unwrap();
60
61                assert_eq!(out_f, decimal_f);
62
63                Ok(())
64            })
65            .unwrap();
66    }
67
68    #[test]
69    fn int128_18_from_int64_9() {
70        let mut runner = TestRunner::default();
71        let input = Decimal::arbitrary();
72
73        runner
74            .run(&input, |decimal: Decimal<i64, 9>| {
75                let out = Int128_18::from(decimal);
76                let out_f = f64::from_str(&out.to_string()).unwrap();
77                let decimal_f = f64::from_str(&decimal.to_string()).unwrap();
78
79                assert_eq!(out_f, decimal_f);
80
81                Ok(())
82            })
83            .unwrap();
84    }
85
86    generate_tests_for_common_variants!(to_f64_does_not_panic);
87
88    fn to_f64_does_not_panic<I, const D: u8>()
89    where
90        I: ScaledInteger<D> + Arbitrary,
91    {
92        proptest!(|(a: Decimal<I, D>)| {
93            a.to_f64();
94        });
95    }
96}