cassandra_proto/types/
decimal.rs

1use super::{to_int, to_varint};
2use crate::frame::traits::IntoBytes;
3
4/// Cassandra Decimal type
5#[derive(Debug, Clone, PartialEq)]
6pub struct Decimal {
7  pub unscaled: i64,
8  pub scale: u32,
9}
10
11impl Decimal {
12  pub fn new(unscaled: i64, scale: u32) -> Self {
13    Decimal { unscaled, scale }
14  }
15
16  /// Method that returns plain `f64` value.
17  pub fn as_plain(&self) -> f64 {
18    (self.unscaled as f64) / (10i64.pow(self.scale) as f64)
19  }
20}
21
22impl IntoBytes for Decimal {
23  fn into_cbytes(&self) -> Vec<u8> {
24    let mut bytes: Vec<u8> = vec![];
25    bytes.extend(to_int(self.scale as i32));
26    bytes.extend(to_varint(self.unscaled));
27
28    bytes
29  }
30}
31
32macro_rules! impl_from_for_decimal {
33  ($t:ty) => {
34    impl From<$t> for Decimal {
35      fn from(i: $t) -> Self {
36        Decimal {
37          unscaled: i as i64,
38          scale: 0,
39        }
40      }
41    }
42  };
43}
44
45impl_from_for_decimal!(i8);
46impl_from_for_decimal!(i16);
47impl_from_for_decimal!(i32);
48impl_from_for_decimal!(i64);
49impl_from_for_decimal!(u8);
50impl_from_for_decimal!(u16);
51
52impl From<f32> for Decimal {
53  fn from(f: f32) -> Decimal {
54    let mut scale: u32 = 0;
55
56    loop {
57      let unscaled = f * (10i64.pow(scale) as f32);
58
59      if unscaled == unscaled.trunc() {
60        return Decimal::new(unscaled as i64, scale);
61      }
62
63      scale += 1;
64    }
65  }
66}
67
68impl From<f64> for Decimal {
69  fn from(f: f64) -> Decimal {
70    let mut scale: u32 = 0;
71
72    loop {
73      let unscaled = f * (10i64.pow(scale) as f64);
74
75      if unscaled == unscaled.trunc() {
76        return Decimal::new(unscaled as i64, scale);
77      }
78
79      scale += 1;
80    }
81  }
82}
83
84#[cfg(test)]
85mod test {
86  use super::*;
87
88  #[test]
89  fn into_cbytes_test() {
90    assert_eq!(
91      Decimal::new(129, 0).into_cbytes(),
92      vec![0, 0, 0, 0, 0x00, 0x81]
93    );
94
95    assert_eq!(
96      Decimal::new(-129, 0).into_cbytes(),
97      vec![0, 0, 0, 0, 0xFF, 0x7F]
98    );
99
100    let expected: Vec<u8> = vec![0, 0, 0, 1, 0x00, 0x81];
101    assert_eq!(Decimal::new(129, 1).into_cbytes(), expected);
102
103    let expected: Vec<u8> = vec![0, 0, 0, 1, 0xFF, 0x7F];
104    assert_eq!(Decimal::new(-129, 1).into_cbytes(), expected);
105  }
106
107  #[test]
108  fn from_f32() {
109    assert_eq!(Decimal::from(12300001 as f32), Decimal::new(12300001, 0));
110    assert_eq!(Decimal::from(1230000.1 as f32), Decimal::new(12300001, 1));
111    assert_eq!(Decimal::from(0.12300001 as f32), Decimal::new(12300001, 8));
112  }
113
114  #[test]
115  fn from_f64() {
116    assert_eq!(
117      Decimal::from(1230000000000001i64 as f64),
118      Decimal::new(1230000000000001i64, 0)
119    );
120    assert_eq!(
121      Decimal::from(123000000000000.1f64),
122      Decimal::new(1230000000000001i64, 1)
123    );
124    assert_eq!(
125      Decimal::from(0.1230000000000001f64),
126      Decimal::new(1230000000000001i64, 16)
127    );
128  }
129}