1use super::number_format::{self, NumberParseError};
18use super::{NumberFormatInfo, NumberStyles};
19use crate::data::converters::composite_format::FormatError;
20use crate::data::core::ValueTypes;
21use std::fmt;
22use std::ops::{Add, AddAssign, Div, Neg, Sub, SubAssign};
23use std::str::FromStr;
24
25const MAX_MANTISSA: u128 = (1u128 << 96) - 1;
27
28const MAX_SCALE: u8 = 28;
30
31const OVERFLOW: &str = "Value was either too large or too small for a Decimal.";
32
33const DOUBLE_POWERS_10: [f64; 29] = [
35 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19,
36 1e20, 1e21, 1e22, 1e23, 1e24, 1e25, 1e26, 1e27, 1e28,
37];
38
39#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
41pub struct Decimal(rust_decimal::Decimal);
42
43impl Decimal {
44 pub const ZERO: Decimal = Decimal(rust_decimal::Decimal::ZERO);
46
47 pub const ONE: Decimal = Decimal(rust_decimal::Decimal::ONE);
49
50 pub const MAX_VALUE: Decimal = Decimal(rust_decimal::Decimal::MAX);
52
53 pub const MIN_VALUE: Decimal = Decimal(rust_decimal::Decimal::MIN);
55
56 pub fn from_parts(mantissa: u128, scale: u8, negative: bool) -> Decimal {
61 assert!(mantissa <= MAX_MANTISSA, "The mantissa of a Decimal has at most 96 bits.");
62 assert!(scale <= MAX_SCALE, "Decimal's scale value must be between 0 and 28, inclusive.");
63 let mut value = rust_decimal::Decimal::from_i128_with_scale(mantissa as i128, u32::from(scale));
64 value.set_sign_negative(negative);
65 Decimal(value)
66 }
67
68 #[inline]
70 pub fn mantissa(&self) -> u128 {
71 self.0.mantissa().unsigned_abs()
72 }
73
74 #[inline]
76 pub fn scale(&self) -> u8 {
77 self.0.scale() as u8
78 }
79
80 #[inline]
83 pub fn is_sign_negative(&self) -> bool {
84 self.0.is_sign_negative()
85 }
86
87 #[inline]
89 pub fn is_zero(&self) -> bool {
90 self.0.is_zero()
91 }
92
93 fn at_scale_of(result: rust_decimal::Decimal, a: Decimal, b: Decimal) -> Decimal {
97 let scale = u32::from(a.scale().max(b.scale()));
98 let mut result_scale = result.scale();
99 if result_scale >= scale {
100 return Decimal(result);
101 }
102
103 let mut mantissa = result.mantissa().unsigned_abs();
105 while result_scale < scale {
106 match mantissa.checked_mul(10) {
107 Some(next) if next <= MAX_MANTISSA => {
108 mantissa = next;
109 result_scale += 1;
110 }
111 _ => break,
112 }
113 }
114 let mut rescaled = rust_decimal::Decimal::from_i128_with_scale(mantissa as i128, result_scale);
115 rescaled.set_sign_negative(result.is_sign_negative());
116 Decimal(rescaled)
117 }
118
119 #[inline]
122 pub fn max(self, other: Decimal) -> Decimal {
123 if self >= other {
124 self
125 } else {
126 other
127 }
128 }
129
130 #[inline]
133 pub fn min(self, other: Decimal) -> Decimal {
134 if self < other {
135 self
136 } else {
137 other
138 }
139 }
140
141 #[inline]
143 pub fn checked_add(self, other: Decimal) -> Option<Decimal> {
144 self.0.checked_add(other.0).map(|result| Self::at_scale_of(result, self, other))
145 }
146
147 #[inline]
149 pub fn checked_sub(self, other: Decimal) -> Option<Decimal> {
150 self.0.checked_sub(other.0).map(|result| Self::at_scale_of(result, self, other))
151 }
152
153 pub fn checked_div(self, other: Decimal) -> Option<Decimal> {
156 assert!(!other.is_zero(), "Attempted to divide by zero.");
157 let mut quotient = self.0.checked_div(other.0)?;
158 if self.mantissa() % other.mantissa() == 0 {
162 quotient.rescale(u32::from(self.scale().saturating_sub(other.scale())));
163 Some(Decimal(quotient))
164 } else {
165 Some(Decimal(quotient.normalize()))
166 }
167 }
168
169 pub fn to_f64(&self) -> f64 {
172 const TWO_TO_64: f64 = 1.8446744073709552e+019;
175
176 let mantissa = self.mantissa();
177 let low64 = mantissa as u64;
178 let high = (mantissa >> 64) as u32;
179 let dbl = (low64 as f64 + f64::from(high) * TWO_TO_64) / DOUBLE_POWERS_10[usize::from(self.scale())];
180
181 if self.is_sign_negative() {
182 -dbl
183 } else {
184 dbl
185 }
186 }
187
188 #[inline]
191 pub fn to_f32(&self) -> f32 {
192 self.to_f64() as f32
193 }
194
195 pub fn round_to_integer(&self) -> i128 {
199 let mantissa = self.mantissa();
200 let divisor = 10u128.pow(u32::from(self.scale()));
201 let mut integer = mantissa / divisor;
202 let remainder = mantissa % divisor;
203 let half = divisor / 2;
205 if remainder > half || (remainder == half && remainder != 0 && integer % 2 == 1) {
206 integer += 1;
207 }
208
209 if self.is_sign_negative() {
211 -(integer as i128)
212 } else {
213 integer as i128
214 }
215 }
216
217 pub fn from_f64(value: f64) -> Decimal {
222 Self::try_from_f64(value).unwrap_or_else(|| panic!("{OVERFLOW}"))
223 }
224
225 pub fn from_f32(value: f32) -> Decimal {
230 Self::try_from_f32(value).unwrap_or_else(|| panic!("{OVERFLOW}"))
231 }
232
233 pub fn try_from_f32(value: f32) -> Option<Decimal> {
235 const SNG_BIAS: i32 = 126;
238 let exp = ((value.to_bits() >> 23) & 0xFF) as i32 - SNG_BIAS;
239 if exp < -94 {
240 return Some(Decimal::ZERO);
241 }
242
243 if exp > 96 {
245 return None;
246 }
247
248 let negative = value < 0.0;
249 let mut dbl = f64::from(value.abs());
250
251 let mut power = 6 - ((exp * 19728) >> 16);
254 if power >= 0 {
257 if power > i32::from(MAX_SCALE) {
259 power = i32::from(MAX_SCALE);
260 }
261
262 dbl *= DOUBLE_POWERS_10[power as usize];
263 } else if power != -1 || dbl >= 1E7 {
264 dbl /= DOUBLE_POWERS_10[(-power) as usize];
265 } else {
266 power = 0; }
268
269 if dbl < 1E6 && power < i32::from(MAX_SCALE) {
270 dbl *= 10.0;
271 power += 1;
272 }
273
274 let mut mant = dbl.round_ties_even() as u64;
276 if mant == 0 {
277 return Some(Decimal::ZERO);
278 }
279
280 if power < 0 {
281 Some(Decimal::from_parts(u128::from(mant) * 10u128.pow((-power) as u32), 0, negative))
283 } else {
284 let mut lmax = power.min(6);
288 while lmax > 0 && mant % 10 == 0 {
289 mant /= 10;
290 power -= 1;
291 lmax -= 1;
292 }
293
294 Some(Decimal::from_parts(u128::from(mant), power as u8, negative))
295 }
296 }
297
298 pub fn try_from_f64(value: f64) -> Option<Decimal> {
300 const DBL_BIAS: i32 = 1022;
304 let exp = ((value.to_bits() >> 52) & 0x7FF) as i32 - DBL_BIAS;
305 if exp < -94 {
306 return Some(Decimal::ZERO);
307 }
308
309 if exp > 96 {
311 return None;
312 }
313
314 let negative = value < 0.0;
315 let mut dbl = value.abs();
316
317 let mut power = 14 - ((exp * 19728) >> 16);
324 if power >= 0 {
327 if power > i32::from(MAX_SCALE) {
329 power = i32::from(MAX_SCALE);
330 }
331
332 dbl *= DOUBLE_POWERS_10[power as usize];
333 } else if power != -1 || dbl >= 1E15 {
334 dbl /= DOUBLE_POWERS_10[(-power) as usize];
335 } else {
336 power = 0; }
338
339 if dbl < 1E14 && power < i32::from(MAX_SCALE) {
340 dbl *= 10.0;
341 power += 1;
342 }
343
344 let mut mant = dbl.round_ties_even() as u64;
346 if mant == 0 {
347 return Some(Decimal::ZERO);
348 }
349
350 if power < 0 {
351 Some(Decimal::from_parts(u128::from(mant) * 10u128.pow((-power) as u32), 0, negative))
353 } else {
354 let mut lmax = power.min(14);
360 while lmax > 0 && mant % 10 == 0 {
361 mant /= 10;
362 power -= 1;
363 lmax -= 1;
364 }
365
366 Some(Decimal::from_parts(u128::from(mant), power as u8, negative))
367 }
368 }
369
370 pub fn parse(s: &str) -> Result<Decimal, NumberParseError> {
374 number_format::parse_decimal(s, NumberStyles::NUMBER, &NumberFormatInfo::invariant_info())
375 }
376
377 #[inline]
379 pub fn try_parse(s: &str) -> Option<Decimal> {
380 Decimal::parse(s).ok()
381 }
382
383 pub fn parse_with(
390 s: &str,
391 styles: NumberStyles,
392 provider: Option<&NumberFormatInfo>,
393 ) -> Result<Decimal, NumberParseError> {
394 match provider {
395 Some(info) => number_format::parse_decimal(s, styles, info),
396 None => number_format::parse_decimal(s, styles, &NumberFormatInfo::current_info()),
397 }
398 }
399
400 #[inline]
402 pub fn try_parse_with(s: &str, styles: NumberStyles, provider: Option<&NumberFormatInfo>) -> Option<Decimal> {
403 Decimal::parse_with(s, styles, provider).ok()
404 }
405
406 pub fn to_string_with(&self, format: &str, provider: Option<&NumberFormatInfo>) -> Result<String, FormatError> {
410 match provider {
411 Some(info) => number_format::format_decimal(*self, format, info),
412 None => number_format::format_decimal(*self, format, &NumberFormatInfo::current_info()),
413 }
414 }
415
416 pub fn to_string_provider(&self, provider: &NumberFormatInfo) -> String {
419 number_format::format_decimal(*self, "", provider).unwrap_or_default()
420 }
421
422 pub(crate) fn register_value_type() {
426 ValueTypes::register_display::<Decimal>();
427 ValueTypes::register_nullable::<Decimal>();
428 ValueTypes::register_parse::<Decimal>(|s| Decimal::parse(s).ok());
429 ValueTypes::register_conversion::<String, Option<Decimal>>(|s| Decimal::parse(s).ok().map(Some));
430 ValueTypes::register_conversion::<&'static str, Decimal>(|s| Decimal::parse(s).ok());
431 ValueTypes::register_conversion::<&'static str, Option<Decimal>>(|s| Decimal::parse(s).ok().map(Some));
432
433 macro_rules! integers {
434 ($($ty:ty),*) => {
435 $(
436 ValueTypes::register_conversion::<$ty, Decimal>(|v| Some(Decimal::from(*v)));
437 ValueTypes::register_conversion::<$ty, Option<Decimal>>(|v| Some(Some(Decimal::from(*v))));
438 )*
439 };
440 }
441 integers!(i8, i16, i32, i64, u8, u16, u32, u64, isize, usize);
442
443 ValueTypes::register_conversion::<f64, Decimal>(|v| Decimal::try_from_f64(*v));
447 ValueTypes::register_conversion::<f64, Option<Decimal>>(|v| Decimal::try_from_f64(*v).map(Some));
448 ValueTypes::register_conversion::<f32, Decimal>(|v| Decimal::try_from_f32(*v));
449 ValueTypes::register_conversion::<f32, Option<Decimal>>(|v| Decimal::try_from_f32(*v).map(Some));
450 ValueTypes::register_conversion::<Decimal, f64>(|v| Some(v.to_f64()));
451 ValueTypes::register_conversion::<Decimal, Option<f64>>(|v| Some(Some(v.to_f64())));
452 ValueTypes::register_conversion::<Decimal, f32>(|v| Some(v.to_f32()));
453 ValueTypes::register_conversion::<Decimal, Option<f32>>(|v| Some(Some(v.to_f32())));
454
455 macro_rules! to_integers {
459 ($($ty:ty),*) => {
460 $(
461 ValueTypes::register_conversion::<Decimal, $ty>(|v| <$ty>::try_from(v.round_to_integer()).ok());
462 ValueTypes::register_conversion::<Decimal, Option<$ty>>(|v| {
463 <$ty>::try_from(v.round_to_integer()).ok().map(Some)
464 });
465 )*
466 };
467 }
468 to_integers!(i8, i16, i32, i64, u8, u16, u32, u64, isize, usize);
469 }
470}
471
472crate::ferro_markup_type!(struct Decimal {
473 namespace: "System",
474 handles: [Decimal],
475 parse: Decimal::parse,
476 constructors: [() => Decimal::default],
477});
478
479impl Default for Decimal {
480 #[inline]
481 fn default() -> Self {
482 Decimal::ZERO
483 }
484}
485
486impl fmt::Display for Decimal {
487 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
488 f.pad(&self.to_string_provider(&NumberFormatInfo::invariant_info()))
491 }
492}
493
494impl fmt::Debug for Decimal {
495 #[inline]
496 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
497 fmt::Display::fmt(self, f)
498 }
499}
500
501impl FromStr for Decimal {
502 type Err = NumberParseError;
503
504 #[inline]
505 fn from_str(s: &str) -> Result<Self, Self::Err> {
506 Decimal::parse(s)
507 }
508}
509
510macro_rules! from_integers {
511 ($($ty:ty),*) => {
512 $(
513 impl From<$ty> for Decimal {
514 #[inline]
515 fn from(value: $ty) -> Decimal {
516 Decimal(rust_decimal::Decimal::from(value))
517 }
518 }
519 )*
520 };
521}
522
523from_integers!(i8, i16, i32, i64, isize, u8, u16, u32, u64, usize);
524
525impl Neg for Decimal {
526 type Output = Decimal;
527
528 #[inline]
529 fn neg(self) -> Decimal {
530 Decimal(-self.0)
531 }
532}
533
534macro_rules! operators {
535 ($($trait_:ident $method:ident $checked:ident;)*) => {
536 $(
537 impl $trait_ for Decimal {
538 type Output = Decimal;
539
540 #[inline]
541 fn $method(self, other: Decimal) -> Decimal {
542 self.$checked(other).expect(OVERFLOW)
543 }
544 }
545 )*
546 };
547}
548
549operators! {
550 Add add checked_add;
551 Sub sub checked_sub;
552 Div div checked_div;
553}
554
555impl AddAssign for Decimal {
556 #[inline]
557 fn add_assign(&mut self, other: Decimal) {
558 *self = *self + other;
559 }
560}
561
562impl SubAssign for Decimal {
563 #[inline]
564 fn sub_assign(&mut self, other: Decimal) {
565 *self = *self - other;
566 }
567}
568
569#[cfg(test)]
570mod tests {
571 mod double_conversion_data {
572 include!("decimal_double_conversion_data.rs");
573 }
574
575 use super::*;
576 use std::collections::hash_map::DefaultHasher;
577 use std::hash::{Hash, Hasher};
578
579 fn d(text: &str) -> Decimal {
580 Decimal::parse(text).unwrap()
581 }
582
583 fn hash_of(value: Decimal) -> u64 {
584 let mut hasher = DefaultHasher::new();
585 value.hash(&mut hasher);
586 hasher.finish()
587 }
588
589 #[test]
590 fn double_conversions_fail_outside_the_value_range() {
591 assert!(std::panic::catch_unwind(|| Decimal::from_f64(f64::NAN)).is_err());
592 assert!(std::panic::catch_unwind(|| Decimal::from_f64(1e30)).is_err());
593 assert!(std::panic::catch_unwind(|| Decimal::from_f64(f64::INFINITY)).is_err());
594 assert!(!Decimal::from_f64(-0.0).is_sign_negative());
595 assert!(!Decimal::from_f64(-1e-30).is_sign_negative());
596 }
597
598 #[test]
599 fn conversion_from_double_matches_the_managed_runtime() {
600 for &(bits, expected) in double_conversion_data::FROM_DOUBLE {
601 let value = f64::from_bits(bits);
602 if expected == "!" {
603 assert!(std::panic::catch_unwind(|| Decimal::from_f64(value)).is_err(), "{value:e}");
604 } else {
605 assert_eq!(Decimal::from_f64(value).to_string(), expected, "{value:e} ({bits:#018X})");
606 }
607 }
608 }
609
610 #[test]
611 fn conversion_to_double_matches_the_managed_runtime() {
612 for &(text, bits) in double_conversion_data::TO_DOUBLE {
613 let actual = d(text).to_f64();
614 assert_eq!(actual.to_bits(), bits, "{text}: {actual:e} instead of {:e}", f64::from_bits(bits));
615 }
616 }
617
618 #[test]
619 fn constants_and_parts() {
620 assert_eq!(Decimal::MAX_VALUE.to_string(), "79228162514264337593543950335");
621 assert_eq!(Decimal::MIN_VALUE.to_string(), "-79228162514264337593543950335");
622 assert_eq!(Decimal::ZERO.to_string(), "0");
623 assert_eq!(Decimal::ONE.to_string(), "1");
624 assert_eq!(Decimal::from_parts(12345, 3, true).to_string(), "-12.345");
625 assert_eq!(Decimal::from_parts(5, 3, false).to_string(), "0.005");
626 assert_eq!(Decimal::from_parts(110, 2, false).mantissa(), 110);
627 assert_eq!(Decimal::from_parts(110, 2, false).scale(), 2);
628 assert_eq!(Decimal::MAX_VALUE.mantissa(), MAX_MANTISSA);
629 assert!(Decimal::from_parts(0, 1, true).is_sign_negative());
630 assert!(Decimal::from_parts(0, 1, true).is_zero());
631 assert_eq!(Decimal::default(), Decimal::ZERO);
632 }
633
634 #[test]
635 fn display_preserves_trailing_zeros() {
636 assert_eq!(d("1.10").to_string(), "1.10");
637 assert_eq!(d("1.1").to_string(), "1.1");
638 assert_eq!(d("0.00").to_string(), "0.00");
639 assert_eq!(d("-0.0").to_string(), "0.0");
640 assert_eq!(d("100").to_string(), "100");
641 assert_eq!(d("0.0000000000000000000000000001").to_string(), "0.0000000000000000000000000001");
642 assert_eq!(format!("{:>6}", d("1.5")), " 1.5");
643 assert_eq!(format!("{:?}", d("1.50")), "1.50");
644 }
645
646 #[test]
647 fn equality_ordering_and_hash_are_by_value() {
648 assert_eq!(d("1.10"), d("1.1"));
649 assert_eq!(hash_of(d("1.10")), hash_of(d("1.1")));
650 assert_eq!(d("0.00"), Decimal::ZERO);
651 assert_eq!(d("-0"), Decimal::ZERO);
652 assert_eq!(hash_of(d("-0.00")), hash_of(Decimal::ZERO));
653 assert!(d("1.1") < d("1.11"));
654 assert!(d("-1.1") > d("-1.11"));
655 assert!(d("-1") < d("0.5"));
656 assert!(Decimal::MIN_VALUE < Decimal::MAX_VALUE);
657 assert!(Decimal::MAX_VALUE > d("0.0000000000000000000000000001"));
658 assert_eq!(d("2").max(d("3.0")).to_string(), "3.0");
659 assert_eq!(d("5").min(d("3.0")).to_string(), "3.0");
660 assert_eq!(d("5").clamp(d("200"), d("400")), d("200"));
661 }
662
663 #[test]
664 fn addition_and_subtraction_take_the_larger_scale() {
665 assert_eq!((d("1.10") + d("2.2")).to_string(), "3.30");
666 assert_eq!((d("1.1") - d("1.10")).to_string(), "0.00");
667 assert_eq!((d("1") - d("3")).to_string(), "-2");
668 assert_eq!((d("-1.5") + d("1.5")).to_string(), "0.0");
669 assert_eq!((d("0.1") + d("0.2")), d("0.3"));
670 assert_eq!((d("5") + Decimal::ONE).to_string(), "6");
671 assert_eq!((d("10.11") + Decimal::ONE).to_string(), "11.11");
672 assert_eq!((Decimal::MAX_VALUE - Decimal::ONE).to_string(), "79228162514264337593543950334");
673 let mut value = d("1.5");
674 value += d("1");
675 value -= d("0.25");
676 assert_eq!(value.to_string(), "2.25");
677 assert_eq!((-d("1.50")).to_string(), "-1.50");
678 }
679
680 #[test]
681 fn a_sum_with_a_zero_of_a_larger_scale_takes_the_largest_scale_that_fits() {
682 assert_eq!(
684 (d("0.000000000000000000000000000") + d("857337436073678641268323889")).to_string(),
685 "857337436073678641268323889.0"
686 );
687 assert_eq!(
688 (d("0.000000000000000000000000000") - d("857337436073678641268323889")).to_string(),
689 "-857337436073678641268323889.0"
690 );
691 assert_eq!(
692 (d("434.559") + d("0.0000000000000000000000000000")).to_string(),
693 "434.55900000000000000000000000"
694 );
695 assert_eq!(
696 (d("-4128645094226724.54") - d("-0.00000000000000000000")).to_string(),
697 "-4128645094226724.5400000000000"
698 );
699 assert_eq!((Decimal::MAX_VALUE + d("0.00")).to_string(), "79228162514264337593543950335");
700 assert_eq!((d("5") + d("0.00")).to_string(), "5.00");
701 }
702
703 #[test]
704 fn max_and_min_of_equal_values_are_those_of_the_managed_runtime() {
705 assert_eq!(d("5.00").max(d("5")).to_string(), "5.00");
707 assert_eq!(d("5").max(d("5.00")).to_string(), "5");
708 assert_eq!(d("5.00").min(d("5")).to_string(), "5");
709 assert_eq!(d("5").min(d("5.00")).to_string(), "5.00");
710 assert_eq!(d("-0.0").max(d("0")).to_string(), "0.0");
711 assert_eq!(d("2").max(d("3.0")).to_string(), "3.0");
712 assert_eq!(d("5").min(d("3.0")).to_string(), "3.0");
713 }
714
715 #[test]
716 #[should_panic(expected = "Value was either too large or too small for a Decimal.")]
717 fn addition_overflow_panics() {
718 let _ = Decimal::MAX_VALUE + Decimal::ONE;
719 }
720
721 #[test]
722 fn checked_operations_report_overflow() {
723 assert_eq!(Decimal::MAX_VALUE.checked_add(Decimal::ONE), None);
724 assert_eq!(Decimal::MIN_VALUE.checked_sub(Decimal::ONE), None);
725 assert_eq!(Decimal::MAX_VALUE.checked_div(d("0.1")), None);
726 assert_eq!(Decimal::MAX_VALUE.checked_add(Decimal::MIN_VALUE), Some(Decimal::ZERO));
727 }
728
729 #[test]
730 fn division() {
731 assert_eq!((d("10.11") / Decimal::from(100)).to_string(), "0.1011");
733 assert_eq!((d("1011.00") / Decimal::from(100)).to_string(), "10.11");
734 assert_eq!((d("50") / Decimal::from(100)).to_string(), "0.5");
735 assert_eq!((d("-1") / d("4")).to_string(), "-0.25");
736 assert_eq!((d("1") / d("3")).to_string(), "0.3333333333333333333333333333");
737 assert_eq!((d("6.00") / d("2")).to_string(), "3.00");
738 assert_eq!((d("6") / d("2.00")).to_string(), "3");
739 assert_eq!((d("1.00") / d("8")).to_string(), "0.125");
740 assert_eq!((d("0") / d("7")).to_string(), "0");
741 }
742
743 #[test]
744 #[should_panic(expected = "Attempted to divide by zero.")]
745 fn division_by_zero_panics() {
746 let _ = Decimal::ONE / Decimal::ZERO;
747 }
748
749 #[test]
750 fn integer_conversions() {
751 assert_eq!(Decimal::from(42i32).to_string(), "42");
752 assert_eq!(Decimal::from(-42i64).to_string(), "-42");
753 assert_eq!(Decimal::from(i64::MIN).to_string(), "-9223372036854775808");
754 assert_eq!(Decimal::from(u64::MAX).to_string(), "18446744073709551615");
755 }
756
757 #[test]
758 fn single_conversions() {
759 assert_eq!(Decimal::from_f32(0.1).to_string(), "0.1");
761 assert_eq!(Decimal::from_f32(-2.5).to_string(), "-2.5");
762 assert_eq!(Decimal::from_f32(1234.5).to_string(), "1234.5");
763 assert_eq!(Decimal::from_f32(16777216.0).to_string(), "16777220");
764 assert_eq!(Decimal::from_f32(1e10).to_string(), "10000000000");
765 assert_eq!(Decimal::from_f32(0.0).to_string(), "0");
766 assert!(!Decimal::from_f32(-1e-30).is_sign_negative());
767 assert_eq!(Decimal::try_from_f32(f32::NAN), None);
768 assert_eq!(Decimal::try_from_f32(f32::INFINITY), None);
769 assert_eq!(Decimal::try_from_f32(1e30), None);
770 assert!(std::panic::catch_unwind(|| Decimal::from_f32(f32::NEG_INFINITY)).is_err());
771 assert_eq!(Decimal::try_from_f64(f64::NAN), None);
772 assert_eq!(Decimal::try_from_f64(-1e30), None);
773 assert_eq!(Decimal::try_from_f64(2.5), Some(d("2.5")));
774
775 assert_eq!(d("0.5").to_f32(), 0.5);
776 assert_eq!(d("0.1").to_f32(), 0.1f32);
777 assert_eq!(Decimal::MAX_VALUE.to_f32(), 7.9228163e28);
778 }
779
780 #[test]
781 fn rounding_to_an_integer_takes_midpoints_to_even() {
782 assert_eq!(d("0").round_to_integer(), 0);
783 assert_eq!(d("7").round_to_integer(), 7);
784 assert_eq!(d("0.5").round_to_integer(), 0);
785 assert_eq!(d("1.5").round_to_integer(), 2);
786 assert_eq!(d("2.5").round_to_integer(), 2);
787 assert_eq!(d("2.50").round_to_integer(), 2);
788 assert_eq!(d("2.51").round_to_integer(), 3);
789 assert_eq!(d("2.49").round_to_integer(), 2);
790 assert_eq!(d("-1.5").round_to_integer(), -2);
791 assert_eq!(d("-2.5").round_to_integer(), -2);
792 assert_eq!(d("-0.4").round_to_integer(), 0);
793 assert_eq!(Decimal::MAX_VALUE.round_to_integer(), MAX_MANTISSA as i128);
794 assert_eq!(Decimal::MIN_VALUE.round_to_integer(), -(MAX_MANTISSA as i128));
795 }
796
797 #[test]
798 fn parse_and_from_str() {
799 assert_eq!("1.10".parse::<Decimal>().unwrap().to_string(), "1.10");
800 assert_eq!(d(" -1,234.50 ").to_string(), "-1234.50");
801 assert_eq!(d("5-").to_string(), "-5");
802 assert_eq!(d("+5").to_string(), "5");
803 assert_eq!(d(".5").to_string(), "0.5");
804 assert_eq!(d("5.").to_string(), "5");
805 assert_eq!(Decimal::parse(""), Err(NumberParseError::Format));
806 assert_eq!(Decimal::parse("abc"), Err(NumberParseError::Format));
807 assert_eq!(Decimal::parse("1e2"), Err(NumberParseError::Format));
808 assert_eq!(Decimal::parse("$5"), Err(NumberParseError::Format));
809 assert_eq!(Decimal::parse("79228162514264337593543950336"), Err(NumberParseError::Overflow));
810 assert_eq!(Decimal::try_parse("x"), None);
811 assert_eq!(d("79228162514264337593543950335"), Decimal::MAX_VALUE);
812 assert_eq!(d("-79228162514264337593543950335"), Decimal::MIN_VALUE);
813 assert_eq!(d("0.00000000000000000000000000005").to_string(), "0.0000000000000000000000000000");
815 assert_eq!(d("0.00000000000000000000000000015").to_string(), "0.0000000000000000000000000002");
816 assert_eq!(d("0.000000000000000000000000000051").to_string(), "0.0000000000000000000000000001");
817 assert_eq!(d("1.00000000000000000000000000005").to_string(), "1.0000000000000000000000000000");
818 assert_eq!(d("7922816251426433759354395033.55").to_string(), "7922816251426433759354395034");
819 }
820
821 #[test]
822 fn untyped_conversions() {
823 use crate::data::core::ValueType;
824 use crate::BoxedValue;
825 use std::rc::Rc;
826
827 let convert = |value: BoxedValue, target: ValueType| ValueTypes::try_convert_registered(&value, target);
828 let text: BoxedValue = Rc::new("1.50".to_string());
829 let converted = convert(text, ValueType::of::<Decimal>()).unwrap();
830 assert_eq!(converted.downcast_ref::<Decimal>().unwrap().to_string(), "1.50");
831
832 let number: BoxedValue = Rc::new(7i32);
833 let converted = convert(number, ValueType::of::<Option<Decimal>>()).unwrap();
834 assert_eq!(converted.downcast_ref::<Option<Decimal>>(), Some(&Some(d("7"))));
835
836 let value: BoxedValue = Rc::new(d("2.5"));
837 assert_eq!(
838 convert(value.clone(), ValueType::of::<Option<Decimal>>()).unwrap().downcast_ref::<Option<Decimal>>(),
839 Some(&Some(d("2.5")))
840 );
841 assert_eq!(ValueTypes::to_display_string(Some(&value)), "2.5");
842
843 assert!(ValueTypes::accepts_null(ValueType::of::<Option<Decimal>>()));
844 assert!(!ValueTypes::accepts_null(ValueType::of::<Decimal>()));
845 }
846}