cassandra_protocol/types/
decimal.rs1use derive_more::Constructor;
2use float_eq::*;
3use num_bigint::BigInt;
4use std::io::Cursor;
5
6use crate::frame::{Serialize, Version};
7
8#[derive(Debug, Clone, PartialEq, Constructor, Ord, PartialOrd, Eq, Hash)]
10pub struct Decimal {
11 pub unscaled: BigInt,
12 pub scale: i32,
13}
14
15impl Decimal {
16 pub fn as_plain(&self) -> BigInt {
18 self.unscaled.clone() / 10i64.pow(self.scale as u32)
19 }
20}
21
22impl Serialize for Decimal {
23 fn serialize(&self, cursor: &mut Cursor<&mut Vec<u8>>, version: Version) {
24 self.scale.serialize(cursor, version);
25 self.unscaled
26 .to_signed_bytes_be()
27 .serialize(cursor, version);
28 }
29}
30
31macro_rules! impl_from_for_decimal {
32 ($t:ty) => {
33 impl From<$t> for Decimal {
34 fn from(i: $t) -> Self {
35 Decimal {
36 unscaled: i.into(),
37 scale: 0,
38 }
39 }
40 }
41 };
42}
43
44impl_from_for_decimal!(i8);
45impl_from_for_decimal!(i16);
46impl_from_for_decimal!(i32);
47impl_from_for_decimal!(i64);
48impl_from_for_decimal!(u8);
49impl_from_for_decimal!(u16);
50
51impl From<f32> for Decimal {
52 fn from(f: f32) -> Decimal {
53 let mut scale = 0;
54
55 loop {
56 let unscaled = f * (10i64.pow(scale) as f32);
57
58 if float_eq!(unscaled, unscaled.trunc(), abs <= f32::EPSILON) {
59 return Decimal::new((unscaled as i64).into(), scale as i32);
60 }
61
62 scale += 1;
63 }
64 }
65}
66
67impl From<f64> for Decimal {
68 fn from(f: f64) -> Decimal {
69 let mut scale = 0;
70
71 loop {
72 let unscaled = f * (10i64.pow(scale) as f64);
73
74 if float_eq!(unscaled, unscaled.trunc(), abs <= f64::EPSILON) {
75 return Decimal::new((unscaled as i64).into(), scale as i32);
76 }
77
78 scale += 1;
79 }
80 }
81}
82
83impl From<Decimal> for BigInt {
84 fn from(value: Decimal) -> Self {
85 value.as_plain()
86 }
87}
88
89#[cfg(test)]
90mod test {
91 use super::*;
92
93 #[test]
94 fn serialize_test() {
95 assert_eq!(
96 Decimal::new(129.into(), 0).serialize_to_vec(Version::V4),
97 vec![0, 0, 0, 0, 0x00, 0x81]
98 );
99
100 assert_eq!(
101 Decimal::new(BigInt::from(-129), 0).serialize_to_vec(Version::V4),
102 vec![0, 0, 0, 0, 0xFF, 0x7F]
103 );
104
105 let expected: Vec<u8> = vec![0, 0, 0, 1, 0x00, 0x81];
106 assert_eq!(
107 Decimal::new(129.into(), 1).serialize_to_vec(Version::V4),
108 expected
109 );
110
111 let expected: Vec<u8> = vec![0, 0, 0, 1, 0xFF, 0x7F];
112 assert_eq!(
113 Decimal::new(BigInt::from(-129), 1).serialize_to_vec(Version::V4),
114 expected
115 );
116 }
117
118 #[test]
119 fn from_f32() {
120 assert_eq!(
121 Decimal::from(12300001_f32),
122 Decimal::new(12300001.into(), 0)
123 );
124 assert_eq!(
125 Decimal::from(1230000.1_f32),
126 Decimal::new(12300001.into(), 1)
127 );
128 assert_eq!(
129 Decimal::from(0.12300001_f32),
130 Decimal::new(12300001.into(), 8)
131 );
132 }
133
134 #[test]
135 fn from_f64() {
136 assert_eq!(
137 Decimal::from(1230000000000001_f64),
138 Decimal::new(1230000000000001i64.into(), 0)
139 );
140 assert_eq!(
141 Decimal::from(123000000000000.1f64),
142 Decimal::new(1230000000000001i64.into(), 1)
143 );
144 assert_eq!(
145 Decimal::from(0.1230000000000001f64),
146 Decimal::new(1230000000000001i64.into(), 16)
147 );
148 }
149}