const_decimal/
conversion.rs

1use crate::{Decimal, Int128_18, Int64_9, ScaledInteger, Uint128_18, Uint64_9};
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
33#[cfg(test)]
34mod tests {
35    use std::str::FromStr;
36
37    use proptest::prelude::Arbitrary;
38    use proptest::proptest;
39    use proptest::test_runner::TestRunner;
40
41    use super::*;
42    use crate::macros::generate_tests_for_common_variants;
43
44    #[test]
45    fn uint128_18_from_uint64_9() {
46        let mut runner = TestRunner::default();
47        let input = Decimal::arbitrary();
48
49        runner
50            .run(&input, |decimal: Decimal<u64, 9>| {
51                let out = Uint128_18::from(decimal);
52                let out_f = f64::from_str(&out.to_string()).unwrap();
53                let decimal_f = f64::from_str(&decimal.to_string()).unwrap();
54
55                assert_eq!(out_f, decimal_f);
56
57                Ok(())
58            })
59            .unwrap();
60    }
61
62    #[test]
63    fn int128_18_from_int64_9() {
64        let mut runner = TestRunner::default();
65        let input = Decimal::arbitrary();
66
67        runner
68            .run(&input, |decimal: Decimal<i64, 9>| {
69                let out = Int128_18::from(decimal);
70                let out_f = f64::from_str(&out.to_string()).unwrap();
71                let decimal_f = f64::from_str(&decimal.to_string()).unwrap();
72
73                assert_eq!(out_f, decimal_f);
74
75                Ok(())
76            })
77            .unwrap();
78    }
79
80    generate_tests_for_common_variants!(to_f64_does_not_panic);
81
82    fn to_f64_does_not_panic<I, const D: u8>()
83    where
84        I: ScaledInteger<D> + Arbitrary,
85    {
86        proptest!(|(a: Decimal<I, D>)| {
87            a.to_f64();
88        });
89    }
90}