1use std::fmt::Display;
16use std::hash::Hash;
17use std::str::FromStr;
18
19use bigdecimal::{BigDecimal, ToPrimitive};
20use rust_decimal::Decimal as RustDecimal;
21use serde::{Deserialize, Serialize};
22use snafu::ResultExt;
23
24use crate::error::{
25 self, BigDecimalOutOfRangeSnafu, Error, InvalidPrecisionOrScaleSnafu, ParseBigDecimalStrSnafu,
26 ParseRustDecimalStrSnafu,
27};
28
29pub const DECIMAL128_MAX_PRECISION: u8 = 38;
31
32pub const DECIMAL128_MAX_SCALE: i8 = 38;
34
35pub const DECIMAL128_DEFAULT_SCALE: i8 = 10;
37
38const BYTES_TO_OVERFLOW_RUST_DECIMAL: usize = 28;
40
41#[derive(Debug, Eq, Copy, Clone, Serialize, Deserialize)]
47pub struct Decimal128 {
48 value: i128,
49 precision: u8,
50 scale: i8,
51}
52
53impl Decimal128 {
54 pub fn new(value: i128, precision: u8, scale: i8) -> Self {
56 debug_assert!(
58 precision > 0 && precision <= DECIMAL128_MAX_PRECISION,
59 "precision should be in [1, {}]",
60 DECIMAL128_MAX_PRECISION
61 );
62 debug_assert!(
63 scale >= 0 && scale <= precision as i8,
64 "scale should be in [0, precision]"
65 );
66 Self {
67 value,
68 precision,
69 scale,
70 }
71 }
72
73 pub fn try_new(value: i128, precision: u8, scale: i8) -> error::Result<Self> {
75 valid_precision_and_scale(precision, scale)?;
77 Ok(Self {
78 value,
79 precision,
80 scale,
81 })
82 }
83
84 pub fn val(&self) -> i128 {
86 self.value
87 }
88
89 pub fn precision(&self) -> u8 {
91 self.precision
92 }
93
94 pub fn scale(&self) -> i8 {
96 self.scale
97 }
98
99 pub fn to_scalar_value(&self) -> (Option<i128>, u8, i8) {
101 (Some(self.value), self.precision, self.scale)
102 }
103
104 pub fn split_value(&self) -> (i64, i64) {
109 ((self.value >> 64) as i64, self.value as i64)
110 }
111
112 pub fn from_value_precision_scale(hi: i64, lo: i64, precision: u8, scale: i8) -> Self {
115 let hi = (hi as u128 & u64::MAX as u128) << 64;
120 let lo = lo as u128 & u64::MAX as u128;
121 let value = (hi | lo) as i128;
122 Self::new(value, precision, scale)
123 }
124
125 pub fn negative(mut self) -> Self {
126 self.value = -self.value;
127 self
128 }
129}
130
131impl Default for Decimal128 {
133 fn default() -> Self {
134 Self {
135 value: 0,
136 precision: 1,
137 scale: 0,
138 }
139 }
140}
141
142impl PartialEq for Decimal128 {
143 fn eq(&self, other: &Self) -> bool {
144 self.precision.eq(&other.precision)
145 && self.scale.eq(&other.scale)
146 && self.value.eq(&other.value)
147 }
148}
149
150impl PartialOrd for Decimal128 {
152 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
153 if self.precision == other.precision && self.scale == other.scale {
154 return self.value.partial_cmp(&other.value);
155 }
156 None
157 }
158}
159
160impl FromStr for Decimal128 {
164 type Err = Error;
165
166 fn from_str(s: &str) -> Result<Self, Self::Err> {
167 let len = s.len();
168 if len <= BYTES_TO_OVERFLOW_RUST_DECIMAL {
169 let rd = RustDecimal::from_str_exact(s).context(ParseRustDecimalStrSnafu { raw: s })?;
170 Ok(Self::from(rd))
171 } else {
172 let bd = BigDecimal::from_str(s).context(ParseBigDecimalStrSnafu { raw: s })?;
173 Self::try_from(bd)
174 }
175 }
176}
177
178impl Display for Decimal128 {
179 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
180 write!(
181 f,
182 "{}",
183 format_decimal_str(&self.value.to_string(), self.precision as usize, self.scale)
184 )
185 }
186}
187
188impl Hash for Decimal128 {
189 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
190 state.write_i128(self.value);
191 state.write_u8(self.precision);
192 state.write_i8(self.scale);
193 }
194}
195
196impl From<Decimal128> for serde_json::Value {
197 fn from(decimal: Decimal128) -> Self {
198 serde_json::Value::String(decimal.to_string())
199 }
200}
201
202impl From<Decimal128> for i128 {
203 fn from(decimal: Decimal128) -> Self {
204 decimal.val()
205 }
206}
207
208impl From<i128> for Decimal128 {
209 fn from(value: i128) -> Self {
210 Self {
211 value,
212 precision: DECIMAL128_MAX_PRECISION,
213 scale: DECIMAL128_DEFAULT_SCALE,
214 }
215 }
216}
217
218impl From<RustDecimal> for Decimal128 {
222 fn from(rd: RustDecimal) -> Self {
223 let s = rd.to_string();
224 let precision = (s.len() - s.matches(&['.', '-'][..]).count()) as u8;
225 Self {
226 value: rd.mantissa(),
227 precision,
228 scale: rd.scale() as i8,
229 }
230 }
231}
232
233impl TryFrom<BigDecimal> for Decimal128 {
238 type Error = Error;
239
240 fn try_from(value: BigDecimal) -> Result<Self, Self::Error> {
241 let precision = value.digits();
242 let (big_int, scale) = value.as_bigint_and_exponent();
243 big_int
245 .to_i128()
246 .map(|val| Self::try_new(val, precision as u8, scale as i8))
247 .unwrap_or_else(|| BigDecimalOutOfRangeSnafu { value }.fail())
248 }
249}
250
251fn format_decimal_str(value_str: &str, precision: usize, scale: i8) -> String {
254 let (sign, rest) = match value_str.strip_prefix('-') {
255 Some(stripped) => ("-", stripped),
256 None => ("", value_str),
257 };
258
259 let bound = precision.min(rest.len()) + sign.len();
260 let value_str = &value_str[0..bound];
261
262 if scale == 0 {
263 value_str.to_string()
264 } else if scale < 0 {
265 let padding = value_str.len() + scale.unsigned_abs() as usize;
266 format!("{value_str:0<padding$}")
267 } else if rest.len() > scale as usize {
268 let (whole, decimal) = value_str.split_at(value_str.len() - scale as usize);
270 format!("{whole}.{decimal}")
271 } else {
272 format!("{}0.{:0>width$}", sign, rest, width = scale as usize)
274 }
275}
276
277fn valid_precision_and_scale(precision: u8, scale: i8) -> error::Result<()> {
279 if precision == 0 {
280 return InvalidPrecisionOrScaleSnafu {
281 reason: format!(
282 "precision cannot be 0, has to be between [1, {}]",
283 DECIMAL128_MAX_PRECISION
284 ),
285 }
286 .fail();
287 }
288 if precision > DECIMAL128_MAX_PRECISION {
289 return InvalidPrecisionOrScaleSnafu {
290 reason: format!(
291 "precision {} is greater than max {}",
292 precision, DECIMAL128_MAX_PRECISION
293 ),
294 }
295 .fail();
296 }
297 if scale > DECIMAL128_MAX_SCALE {
298 return InvalidPrecisionOrScaleSnafu {
299 reason: format!(
300 "scale {} is greater than max {}",
301 scale, DECIMAL128_MAX_SCALE
302 ),
303 }
304 .fail();
305 }
306 if scale > 0 && scale > precision as i8 {
307 return InvalidPrecisionOrScaleSnafu {
308 reason: format!("scale {} is greater than precision {}", scale, precision),
309 }
310 .fail();
311 }
312
313 Ok(())
314}
315
316#[cfg(test)]
317mod tests {
318 use super::*;
319
320 #[test]
321 fn test_common_decimal128() {
322 let decimal = Decimal128::new(123456789, 9, 3);
323 assert_eq!(decimal.to_string(), "123456.789");
324
325 let decimal = Decimal128::try_new(123456789, 9, 0);
326 assert_eq!(decimal.unwrap().to_string(), "123456789");
327
328 let decimal = Decimal128::try_new(123456789, 9, 2);
329 assert_eq!(decimal.unwrap().to_string(), "1234567.89");
330
331 let decimal = Decimal128::try_new(123, 3, -2);
332 assert_eq!(decimal.unwrap().to_string(), "12300");
333
334 let decimal = Decimal128::try_new(123, 0, 0);
338 assert!(decimal.is_err());
339
340 let decimal = Decimal128::try_new(123, 39, 0);
342 assert!(decimal.is_err());
343
344 let decimal = Decimal128::try_new(123, 38, 39);
346 assert!(decimal.is_err());
347
348 let decimal = Decimal128::try_new(123, 3, 4);
350 assert!(decimal.is_err());
351 }
352
353 #[test]
354 fn test_decimal128_from_str() {
355 let decimal = Decimal128::from_str("1234567890.123456789").unwrap();
357 assert_eq!(decimal.to_string(), "1234567890.123456789");
358 assert_eq!(decimal.precision(), 19);
359 assert_eq!(decimal.scale(), 9);
360
361 let decimal = Decimal128::from_str("1234567890.123456789012345678").unwrap();
362 assert_eq!(decimal.to_string(), "1234567890.123456789012345678");
363 assert_eq!(decimal.precision(), 28);
364 assert_eq!(decimal.scale(), 18);
365
366 let decimal = Decimal128::from_str("1234567890.1234567890123456789012").unwrap();
368 assert_eq!(decimal.to_string(), "1234567890.1234567890123456789012");
369 assert_eq!(decimal.precision(), 32);
370 assert_eq!(decimal.scale(), 22);
371
372 let decimal = Decimal128::from_str("1234567890.1234567890123456789012345678").unwrap();
373 assert_eq!(
374 decimal.to_string(),
375 "1234567890.1234567890123456789012345678"
376 );
377 assert_eq!(decimal.precision(), 38);
378 assert_eq!(decimal.scale(), 28);
379
380 let decimal = Decimal128::from_str("1234567890.12345678901234567890123456789");
382 assert!(decimal.is_err());
383 }
384
385 #[test]
386 #[ignore]
387 fn test_parse_decimal128_speed() {
388 for _ in 0..1500000 {
390 let _ = RustDecimal::from_str("1234567890.123456789012345678999").unwrap();
391 }
392
393 for _ in 0..1500000 {
395 let _ = BigDecimal::from_str("1234567890.123456789012345678999").unwrap();
396 }
397 }
398
399 #[test]
400 fn test_decimal128_precision_and_scale() {
401 for precision in 1..=38 {
403 for scale in 1..=precision {
404 let decimal_str = format!("0.{}", "1".repeat(scale as usize));
405 let decimal = Decimal128::from_str(&decimal_str).unwrap();
406 assert_eq!(decimal_str, decimal.to_string());
407 }
408 }
409 }
410
411 #[test]
412 fn test_decimal128_compare() {
413 let decimal1 = Decimal128::from_str("1234567890.123456789012345678999").unwrap();
415 let decimal2 = Decimal128::from_str("1234567890.123456789012345678999").unwrap();
416 assert!(decimal1 == decimal2);
417
418 let decimal1 = Decimal128::from_str("1234567890.123456789012345678999").unwrap();
419 let decimal2 = Decimal128::from_str("1234567890.123456789012345678998").unwrap();
420 assert!(decimal1 > decimal2);
421
422 let decimal1 = Decimal128::from_str("1234567890.123456789012345678999").unwrap();
423 let decimal2 = Decimal128::from_str("1234567890.123456789012345678998").unwrap();
424 assert!(decimal2 < decimal1);
425
426 let decimal1 = Decimal128::from_str("1234567890.123456789012345678999").unwrap();
427 let decimal2 = Decimal128::from_str("1234567890.123456789012345678998").unwrap();
428 assert!(decimal1 >= decimal2);
429
430 let decimal1 = Decimal128::from_str("1234567890.123456789012345678999").unwrap();
431 let decimal2 = Decimal128::from_str("1234567890.123456789012345678998").unwrap();
432 assert!(decimal2 <= decimal1);
433
434 let decimal1 = Decimal128::from_str("1234567890.123456789012345678999").unwrap();
435 let decimal2 = Decimal128::from_str("1234567890.123456789012345678998").unwrap();
436 assert!(decimal1 != decimal2);
437
438 let decimal1 = Decimal128::from_str("1234567890.123456789012345678999").unwrap();
440 let decimal2 = Decimal128::from_str("1234567890.123").unwrap();
441 assert_eq!(decimal1.partial_cmp(&decimal2), None);
442 }
443
444 #[test]
445 fn test_convert_with_i128() {
446 let test_decimal128_eq = |value| {
447 let decimal1 =
448 Decimal128::new(value, DECIMAL128_MAX_PRECISION, DECIMAL128_DEFAULT_SCALE);
449 let (hi, lo) = decimal1.split_value();
450 let decimal2 = Decimal128::from_value_precision_scale(
451 hi,
452 lo,
453 DECIMAL128_MAX_PRECISION,
454 DECIMAL128_DEFAULT_SCALE,
455 );
456 assert_eq!(decimal1, decimal2);
457 };
458
459 test_decimal128_eq(1 << 63);
460
461 test_decimal128_eq(0);
462 test_decimal128_eq(1234567890);
463 test_decimal128_eq(-1234567890);
464 test_decimal128_eq(32781372819372817382183218i128);
465 test_decimal128_eq(-32781372819372817382183218i128);
466 test_decimal128_eq(i128::MAX);
467 test_decimal128_eq(i128::MIN);
468 }
469}