|
| 1 | +use crate::{ |
| 2 | + convert::{impl_convert, ConvertFrom}, |
| 3 | + int::ranged_int, |
| 4 | +}; |
| 5 | +use rust_decimal::Decimal; |
| 6 | + |
| 7 | +type Mantissa = [u8; 12]; |
| 8 | +ranged_int!(Scale, u8, 0, Decimal::MAX_SCALE as u8); |
| 9 | +type DecimalEncode = (Mantissa, bool, u8); |
| 10 | +type DecimalDecode = (Mantissa, bool, Scale); |
| 11 | + |
| 12 | +impl ConvertFrom<&Decimal> for DecimalEncode { |
| 13 | + #[inline(always)] |
| 14 | + fn convert_from(value: &Decimal) -> Self { |
| 15 | + let unpacked = value.unpack(); |
| 16 | + let [a0, a1, a2, a3] = unpacked.lo.to_le_bytes(); |
| 17 | + let [b0, b1, b2, b3] = unpacked.mid.to_le_bytes(); |
| 18 | + let [c0, c1, c2, c3] = unpacked.hi.to_le_bytes(); |
| 19 | + ( |
| 20 | + [a0, a1, a2, a3, b0, b1, b2, b3, c0, c1, c2, c3], |
| 21 | + unpacked.negative, |
| 22 | + unpacked.scale as u8, |
| 23 | + ) |
| 24 | + } |
| 25 | +} |
| 26 | + |
| 27 | +impl ConvertFrom<DecimalDecode> for Decimal { |
| 28 | + #[inline(always)] |
| 29 | + fn convert_from(value: DecimalDecode) -> Self { |
| 30 | + let [a0, a1, a2, a3, b0, b1, b2, b3, c0, c1, c2, c3] = value.0; |
| 31 | + let lo = u32::from_le_bytes([a0, a1, a2, a3]); |
| 32 | + let mid = u32::from_le_bytes([b0, b1, b2, b3]); |
| 33 | + let hi = u32::from_le_bytes([c0, c1, c2, c3]); |
| 34 | + let mut ret = Self::from_parts(lo, mid, hi, false, value.2.into_inner() as u32); |
| 35 | + ret.set_sign_negative(value.1); |
| 36 | + ret |
| 37 | + } |
| 38 | +} |
| 39 | + |
| 40 | +impl_convert!(Decimal, DecimalEncode, DecimalDecode); |
| 41 | + |
| 42 | +#[cfg(test)] |
| 43 | +mod tests { |
| 44 | + use crate::{decode, encode}; |
| 45 | + use rust_decimal::Decimal; |
| 46 | + use std::str::FromStr; |
| 47 | + |
| 48 | + #[test] |
| 49 | + fn rust_decimal() { |
| 50 | + assert!(Decimal::MAX_SCALE <= u8::MAX as u32); |
| 51 | + |
| 52 | + let vs = [ |
| 53 | + Decimal::from(0), |
| 54 | + Decimal::from_f64_retain(-0f64).unwrap(), |
| 55 | + Decimal::from(-1), |
| 56 | + Decimal::from(1) / Decimal::from(2), |
| 57 | + Decimal::from(1), |
| 58 | + Decimal::from(999999999999999999u64), |
| 59 | + Decimal::from_str("3.100").unwrap(), |
| 60 | + ]; |
| 61 | + for v in vs { |
| 62 | + let d = decode::<Decimal>(&encode(&v)).unwrap(); |
| 63 | + assert_eq!(d, v); |
| 64 | + assert_eq!(d.is_sign_negative(), v.is_sign_negative()); |
| 65 | + assert_eq!(d.scale(), v.scale()); |
| 66 | + } |
| 67 | + |
| 68 | + assert!(crate::decode::<Decimal>(&crate::encode(&([42u8; 12], false, 28u8))).is_ok()); |
| 69 | + assert!(crate::decode::<Decimal>(&crate::encode(&([42u8; 12], false, 29u8))).is_err()); |
| 70 | + } |
| 71 | + |
| 72 | + use alloc::vec::Vec; |
| 73 | + fn bench_data() -> Vec<Decimal> { |
| 74 | + crate::random_data(1000) |
| 75 | + .into_iter() |
| 76 | + .map(|(n, s): (i64, u32)| Decimal::new(n, s % (Decimal::MAX_SCALE + 1))) |
| 77 | + .collect() |
| 78 | + } |
| 79 | + crate::bench_encode_decode!(decimal_vec: Vec<_>); |
| 80 | +} |
0 commit comments