|
| 1 | +use crate::{ |
| 2 | + convert::{self, ConvertFrom}, |
| 3 | + Decode, Encode, |
| 4 | +}; |
| 5 | +use bytemuck::CheckedBitPattern; |
| 6 | +use rust_decimal::Decimal; |
| 7 | + |
| 8 | +type DecimalConversion = (u32, u32, u32, Flags); |
| 9 | + |
| 10 | +impl ConvertFrom<&Decimal> for DecimalConversion { |
| 11 | + fn convert_from(value: &Decimal) -> Self { |
| 12 | + let unpacked = value.unpack(); |
| 13 | + ( |
| 14 | + unpacked.lo, |
| 15 | + unpacked.mid, |
| 16 | + unpacked.hi, |
| 17 | + Flags::new(unpacked.scale, unpacked.negative), |
| 18 | + ) |
| 19 | + } |
| 20 | +} |
| 21 | + |
| 22 | +impl ConvertFrom<DecimalConversion> for Decimal { |
| 23 | + fn convert_from(value: DecimalConversion) -> Self { |
| 24 | + Self::from_parts( |
| 25 | + value.0, |
| 26 | + value.1, |
| 27 | + value.2, |
| 28 | + value.3.negative(), |
| 29 | + value.3.scale(), |
| 30 | + ) |
| 31 | + } |
| 32 | +} |
| 33 | + |
| 34 | +impl Encode for Decimal { |
| 35 | + type Encoder = convert::ConvertIntoEncoder<DecimalConversion>; |
| 36 | +} |
| 37 | +impl<'a> Decode<'a> for Decimal { |
| 38 | + type Decoder = convert::ConvertFromDecoder<'a, DecimalConversion>; |
| 39 | +} |
| 40 | + |
| 41 | +impl ConvertFrom<&Flags> for u8 { |
| 42 | + fn convert_from(flags: &Flags) -> Self { |
| 43 | + flags.0 |
| 44 | + } |
| 45 | +} |
| 46 | + |
| 47 | +impl Encode for Flags { |
| 48 | + type Encoder = convert::ConvertIntoEncoder<u8>; |
| 49 | +} |
| 50 | + |
| 51 | +/// A u8 guaranteed to satisfy (flags >> 1) <= 28. Prevents Decimal::from_parts from misbehaving. |
| 52 | +#[derive(Copy, Clone)] |
| 53 | +#[repr(transparent)] |
| 54 | +pub struct Flags(u8); |
| 55 | + |
| 56 | +impl Flags { |
| 57 | + #[inline(always)] |
| 58 | + fn new(scale: u32, negative: bool) -> Self { |
| 59 | + Self((scale as u8) << 1 | negative as u8) |
| 60 | + } |
| 61 | + |
| 62 | + #[inline(always)] |
| 63 | + fn scale(&self) -> u32 { |
| 64 | + (self.0 >> 1) as u32 |
| 65 | + } |
| 66 | + |
| 67 | + #[inline(always)] |
| 68 | + fn negative(&self) -> bool { |
| 69 | + self.0 & 1 == 1 |
| 70 | + } |
| 71 | +} |
| 72 | + |
| 73 | +// Safety: u8 and Flags have the same layout since Flags is #[repr(transparent)]. |
| 74 | +unsafe impl CheckedBitPattern for Flags { |
| 75 | + type Bits = u8; |
| 76 | + #[inline(always)] |
| 77 | + fn is_valid_bit_pattern(bits: &Self::Bits) -> bool { |
| 78 | + (*bits >> 1) <= 28 |
| 79 | + } |
| 80 | +} |
| 81 | + |
| 82 | +impl<'a> Decode<'a> for Flags { |
| 83 | + type Decoder = crate::int::CheckedIntDecoder<'a, Flags, u8>; |
| 84 | +} |
0 commit comments