bitcode 0.6.9

bitcode is a bitwise binary serializer
Documentation
use crate::{
    convert::{impl_convert, ConvertFrom},
    int::ranged_int,
};
use rust_decimal::Decimal;

type Mantissa = [u8; 12];
ranged_int!(Scale, u8, 0, Decimal::MAX_SCALE as u8);
type DecimalEncode = (Mantissa, bool, u8);
type DecimalDecode = (Mantissa, bool, Scale);

impl ConvertFrom<&Decimal> for DecimalEncode {
    #[inline(always)]
    fn convert_from(value: &Decimal) -> Self {
        let unpacked = value.unpack();
        let [a0, a1, a2, a3] = unpacked.lo.to_le_bytes();
        let [b0, b1, b2, b3] = unpacked.mid.to_le_bytes();
        let [c0, c1, c2, c3] = unpacked.hi.to_le_bytes();
        (
            [a0, a1, a2, a3, b0, b1, b2, b3, c0, c1, c2, c3],
            unpacked.negative,
            unpacked.scale as u8,
        )
    }
}

impl ConvertFrom<DecimalDecode> for Decimal {
    #[inline(always)]
    fn convert_from(value: DecimalDecode) -> Self {
        let [a0, a1, a2, a3, b0, b1, b2, b3, c0, c1, c2, c3] = value.0;
        let lo = u32::from_le_bytes([a0, a1, a2, a3]);
        let mid = u32::from_le_bytes([b0, b1, b2, b3]);
        let hi = u32::from_le_bytes([c0, c1, c2, c3]);
        let mut ret = Self::from_parts(lo, mid, hi, false, value.2.into_inner() as u32);
        ret.set_sign_negative(value.1);
        ret
    }
}

impl_convert!(Decimal, DecimalEncode, DecimalDecode);

#[cfg(test)]
mod tests {
    use crate::{decode, encode};
    use rust_decimal::Decimal;
    use std::str::FromStr;

    #[test]
    fn rust_decimal() {
        assert!(Decimal::MAX_SCALE <= u8::MAX as u32);

        let vs = [
            Decimal::from(0),
            Decimal::from_f64_retain(-0f64).unwrap(),
            Decimal::from(-1),
            Decimal::from(1) / Decimal::from(2),
            Decimal::from(1),
            Decimal::from(999999999999999999u64),
            Decimal::from_str("3.100").unwrap(),
        ];
        for v in vs {
            let d = decode::<Decimal>(&encode(&v)).unwrap();
            assert_eq!(d, v);
            assert_eq!(d.is_sign_negative(), v.is_sign_negative());
            assert_eq!(d.scale(), v.scale());
        }

        assert!(crate::decode::<Decimal>(&crate::encode(&([42u8; 12], false, 28u8))).is_ok());
        assert!(crate::decode::<Decimal>(&crate::encode(&([42u8; 12], false, 29u8))).is_err());
    }

    use alloc::vec::Vec;
    fn bench_data() -> Vec<Decimal> {
        crate::random_data(1000)
            .into_iter()
            .map(|(n, s): (i64, u32)| Decimal::new(n, s % (Decimal::MAX_SCALE + 1)))
            .collect()
    }
    crate::bench_encode_decode!(decimal_vec: Vec<_>);
}