1use crate::{AvroResult, Error};
19use num_bigint::{BigInt, Sign};
20
21#[derive(Debug, Clone, Eq, serde::Serialize, serde::Deserialize)]
22pub struct Decimal {
23 value: BigInt,
24 len: usize,
25}
26
27impl PartialEq for Decimal {
30 fn eq(&self, other: &Self) -> bool {
31 self.value == other.value
32 }
33}
34
35impl Decimal {
36 pub(crate) fn len(&self) -> usize {
37 self.len
38 }
39
40 pub(crate) fn to_vec(&self) -> AvroResult<Vec<u8>> {
41 self.to_sign_extended_bytes_with_len(self.len)
42 }
43
44 pub(crate) fn to_sign_extended_bytes_with_len(&self, len: usize) -> AvroResult<Vec<u8>> {
45 let sign_byte = 0xFF * u8::from(self.value.sign() == Sign::Minus);
46 let mut decimal_bytes = vec![sign_byte; len];
47 let raw_bytes = self.value.to_signed_bytes_be();
48 let num_raw_bytes = raw_bytes.len();
49 let start_byte_index = len.checked_sub(num_raw_bytes).ok_or(Error::SignExtend {
50 requested: len,
51 needed: num_raw_bytes,
52 })?;
53 decimal_bytes[start_byte_index..].copy_from_slice(&raw_bytes);
54 Ok(decimal_bytes)
55 }
56}
57
58impl From<Decimal> for BigInt {
59 fn from(decimal: Decimal) -> Self {
60 decimal.value
61 }
62}
63
64impl std::convert::TryFrom<&Decimal> for Vec<u8> {
74 type Error = Error;
75
76 fn try_from(decimal: &Decimal) -> Result<Self, Self::Error> {
77 decimal.to_vec()
78 }
79}
80
81impl std::convert::TryFrom<Decimal> for Vec<u8> {
91 type Error = Error;
92
93 fn try_from(decimal: Decimal) -> Result<Self, Self::Error> {
94 decimal.to_vec()
95 }
96}
97
98impl<T: AsRef<[u8]>> From<T> for Decimal {
99 fn from(bytes: T) -> Self {
100 let bytes_ref = bytes.as_ref();
101 Self {
102 value: BigInt::from_signed_bytes_be(bytes_ref),
103 len: bytes_ref.len(),
104 }
105 }
106}
107
108#[cfg(test)]
109mod tests {
110 use super::*;
111 use apache_avro_test_helper::TestResult;
112 use pretty_assertions::assert_eq;
113
114 #[test]
115 fn test_decimal_from_bytes_from_ref_decimal() -> TestResult {
116 let input = vec![1, 24];
117 let d = Decimal::from(&input);
118
119 let output = <Vec<u8>>::try_from(&d)?;
120 assert_eq!(output, input);
121
122 Ok(())
123 }
124
125 #[test]
126 fn test_decimal_from_bytes_from_owned_decimal() -> TestResult {
127 let input = vec![1, 24];
128 let d = Decimal::from(&input);
129
130 let output = <Vec<u8>>::try_from(d)?;
131 assert_eq!(output, input);
132
133 Ok(())
134 }
135
136 #[test]
137 fn avro_3949_decimal_serde() -> TestResult {
138 let decimal = Decimal::from(&[1, 2, 3]);
139
140 let ser = serde_json::to_string(&decimal)?;
141 let de = serde_json::from_str(&ser)?;
142 std::assert_eq!(decimal, de);
143
144 Ok(())
145 }
146}