klirr_core/models/
decimal.rs1use crate::prelude::*;
2use derive_more::FromStr;
3
4#[derive(
14 Clone,
15 Copy,
16 Display,
17 PartialEq,
18 Eq,
19 PartialOrd,
20 Ord,
21 Default,
22 Hash,
23 Debug,
24 From,
25 FromStr,
26 Deref,
27 derive_more::Mul,
28 derive_more::Add,
29 derive_more::Sub,
30 derive_more::AddAssign,
31)]
32#[from(rust_decimal::Decimal, u8, i32)]
33pub struct Decimal(rust_decimal::Decimal);
34
35impl Decimal {
36 pub const ZERO: Self = Self(rust_decimal::Decimal::ZERO);
37 pub const ONE: Self = Self(rust_decimal::Decimal::ONE);
38 pub const TWO: Self = Self(rust_decimal::Decimal::TWO);
39 pub const EIGHT: Self = Self(rust_decimal::Decimal::from_parts(8, 0, 0, false, 0));
40}
41
42use rust_decimal::prelude::{FromPrimitive, ToPrimitive};
43
44impl TryFrom<Decimal> for f64 {
45 type Error = crate::Error;
46 fn try_from(value: Decimal) -> Result<Self> {
47 value
48 .0
49 .to_f64()
50 .ok_or_else(|| Error::InvalidDecimalToF64Conversion {
51 value: value.to_string(),
52 })
53 }
54}
55impl TryFrom<f64> for Decimal {
56 type Error = crate::Error;
57 fn try_from(value: f64) -> Result<Self> {
58 rust_decimal::Decimal::from_f64(value)
59 .ok_or(Error::InvalidDecimalFromF64Conversion { value })
60 .map(Decimal)
61 }
62}
63impl Serialize for Decimal {
64 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
65 where
66 S: serde::Serializer,
67 {
68 f64::try_from(*self)
69 .map_err(serde::ser::Error::custom)
70 .and_then(|f| f.serialize(serializer))
71 }
72}
73
74impl<'de> Deserialize<'de> for Decimal {
75 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
76 where
77 D: serde::Deserializer<'de>,
78 {
79 f64::deserialize(deserializer)
80 .and_then(|f| Decimal::try_from(f).map_err(serde::de::Error::custom))
81 }
82}
83
84#[cfg(test)]
85mod tests {
86 use super::*;
87 use insta::{assert_ron_snapshot, assert_snapshot};
88 use test_log::test;
89
90 type Sut = Decimal;
91
92 #[test]
93 fn test_display() {
94 assert_snapshot!(Sut::EIGHT)
95 }
96
97 #[test]
98 fn test_serde() {
99 assert_ron_snapshot!(Sut::from(dec!(3.14159265)));
100 }
101
102 #[test]
103 fn test_decimal_from_f64_nan() {
104 let result = Sut::try_from(f64::NAN);
105 assert!(result.is_err());
106 }
107}