use super::{to_int, to_varint};
use crate::frame::traits::IntoBytes;
#[derive(Debug, Clone, PartialEq)]
pub struct Decimal {
pub unscaled: i64,
pub scale: u32,
}
impl Decimal {
pub fn new(unscaled: i64, scale: u32) -> Self {
Decimal { unscaled, scale }
}
pub fn as_plain(&self) -> f64 {
(self.unscaled as f64) / (10i64.pow(self.scale) as f64)
}
}
impl IntoBytes for Decimal {
fn into_cbytes(&self) -> Vec<u8> {
let mut bytes: Vec<u8> = vec![];
bytes.extend(to_int(self.scale as i32));
bytes.extend(to_varint(self.unscaled));
bytes
}
}
macro_rules! impl_from_for_decimal {
($t:ty) => {
impl From<$t> for Decimal {
fn from(i: $t) -> Self {
Decimal {
unscaled: i as i64,
scale: 0,
}
}
}
};
}
impl_from_for_decimal!(i8);
impl_from_for_decimal!(i16);
impl_from_for_decimal!(i32);
impl_from_for_decimal!(i64);
impl_from_for_decimal!(u8);
impl_from_for_decimal!(u16);
impl From<f32> for Decimal {
fn from(f: f32) -> Decimal {
let mut scale: u32 = 0;
loop {
let unscaled = f * (10i64.pow(scale) as f32);
if unscaled == unscaled.trunc() {
return Decimal::new(unscaled as i64, scale);
}
scale += 1;
}
}
}
impl From<f64> for Decimal {
fn from(f: f64) -> Decimal {
let mut scale: u32 = 0;
loop {
let unscaled = f * (10i64.pow(scale) as f64);
if unscaled == unscaled.trunc() {
return Decimal::new(unscaled as i64, scale);
}
scale += 1;
}
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn into_cbytes_test() {
assert_eq!(
Decimal::new(129, 0).into_cbytes(),
vec![0, 0, 0, 0, 0x00, 0x81]
);
assert_eq!(
Decimal::new(-129, 0).into_cbytes(),
vec![0, 0, 0, 0, 0xFF, 0x7F]
);
let expected: Vec<u8> = vec![0, 0, 0, 1, 0x00, 0x81];
assert_eq!(Decimal::new(129, 1).into_cbytes(), expected);
let expected: Vec<u8> = vec![0, 0, 0, 1, 0xFF, 0x7F];
assert_eq!(Decimal::new(-129, 1).into_cbytes(), expected);
}
#[test]
fn from_f32() {
assert_eq!(Decimal::from(12300001 as f32), Decimal::new(12300001, 0));
assert_eq!(Decimal::from(1230000.1 as f32), Decimal::new(12300001, 1));
assert_eq!(Decimal::from(0.12300001 as f32), Decimal::new(12300001, 8));
}
#[test]
fn from_f64() {
assert_eq!(
Decimal::from(1230000000000001i64 as f64),
Decimal::new(1230000000000001i64, 0)
);
assert_eq!(
Decimal::from(123000000000000.1f64),
Decimal::new(1230000000000001i64, 1)
);
assert_eq!(
Decimal::from(0.1230000000000001f64),
Decimal::new(1230000000000001i64, 16)
);
}
}