1mod decimal64;
121mod decimal64_no_scale;
122mod encoding;
123
124use std::cmp::Ordering;
125use std::fmt;
126use std::hash::{Hash, Hasher};
127use std::str::FromStr;
128
129use serde::{Deserialize, Deserializer, Serialize, Serializer};
130
131pub use decimal64::{Decimal64, MAX_DECIMAL64_PRECISION, MAX_DECIMAL64_SCALE};
132pub use decimal64_no_scale::{
133 Decimal64NoScale, MAX_DECIMAL64_NO_SCALE_PRECISION, MAX_DECIMAL64_NO_SCALE_SCALE,
134};
135pub use encoding::DecimalError;
136pub use encoding::SpecialValue;
137use encoding::{
138 decode_special_value, decode_to_string, encode_decimal, encode_decimal_with_constraints,
139 encode_special_value, ENCODING_NAN, ENCODING_NEG_INFINITY, ENCODING_POS_INFINITY,
140};
141
142#[derive(Clone)]
155pub struct Decimal {
156 bytes: Vec<u8>,
157}
158
159impl Decimal {
160 pub fn with_precision_scale(
188 s: &str,
189 precision: Option<u32>,
190 scale: Option<i32>,
191 ) -> Result<Self, DecimalError> {
192 let bytes = encode_decimal_with_constraints(s, precision, scale)?;
193 Ok(Self { bytes })
194 }
195
196 pub fn from_bytes(bytes: &[u8]) -> Result<Self, DecimalError> {
213 let _ = decode_to_string(bytes)?;
215 Ok(Self {
216 bytes: bytes.to_vec(),
217 })
218 }
219
220 #[inline]
227 pub fn from_bytes_unchecked(bytes: Vec<u8>) -> Self {
228 Self { bytes }
229 }
230
231 #[inline]
236 pub fn as_bytes(&self) -> &[u8] {
237 &self.bytes
238 }
239
240 #[inline]
242 pub fn into_bytes(self) -> Vec<u8> {
243 self.bytes
244 }
245
246 pub fn is_zero(&self) -> bool {
248 self.bytes.len() == 1 && self.bytes[0] == encoding::SIGN_ZERO
249 }
250
251 pub fn is_negative(&self) -> bool {
253 !self.bytes.is_empty() && self.bytes[0] == encoding::SIGN_NEGATIVE
254 }
255
256 pub fn is_positive(&self) -> bool {
258 !self.bytes.is_empty() && self.bytes[0] == encoding::SIGN_POSITIVE
259 }
260
261 pub fn is_pos_infinity(&self) -> bool {
263 self.bytes.as_slice() == ENCODING_POS_INFINITY
264 }
265
266 pub fn is_neg_infinity(&self) -> bool {
268 self.bytes.as_slice() == ENCODING_NEG_INFINITY
269 }
270
271 pub fn is_infinity(&self) -> bool {
273 self.is_pos_infinity() || self.is_neg_infinity()
274 }
275
276 pub fn is_nan(&self) -> bool {
278 self.bytes.as_slice() == ENCODING_NAN
279 }
280
281 pub fn is_special(&self) -> bool {
283 decode_special_value(&self.bytes).is_some()
284 }
285
286 pub fn is_finite(&self) -> bool {
288 !self.is_special()
289 }
290
291 #[inline]
293 pub fn byte_len(&self) -> usize {
294 self.bytes.len()
295 }
296
297 pub fn infinity() -> Self {
314 Self {
315 bytes: encode_special_value(SpecialValue::Infinity),
316 }
317 }
318
319 pub fn neg_infinity() -> Self {
336 Self {
337 bytes: encode_special_value(SpecialValue::NegInfinity),
338 }
339 }
340
341 pub fn nan() -> Self {
370 Self {
371 bytes: encode_special_value(SpecialValue::NaN),
372 }
373 }
374}
375
376impl FromStr for Decimal {
377 type Err = DecimalError;
378
379 fn from_str(s: &str) -> Result<Self, Self::Err> {
394 let bytes = encode_decimal(s)?;
395 Ok(Self { bytes })
396 }
397}
398
399impl fmt::Display for Decimal {
400 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
401 let s = decode_to_string(&self.bytes).expect("Decimal contains valid bytes");
402 write!(f, "{}", s)
403 }
404}
405
406impl fmt::Debug for Decimal {
407 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
408 let value = decode_to_string(&self.bytes).expect("Decimal contains valid bytes");
409 f.debug_struct("Decimal")
410 .field("value", &value)
411 .field("bytes", &self.bytes)
412 .finish()
413 }
414}
415
416impl PartialEq for Decimal {
417 fn eq(&self, other: &Self) -> bool {
418 self.bytes == other.bytes
419 }
420}
421
422impl Eq for Decimal {}
423
424impl PartialOrd for Decimal {
425 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
426 Some(self.cmp(other))
427 }
428}
429
430impl Ord for Decimal {
431 fn cmp(&self, other: &Self) -> Ordering {
432 self.bytes.cmp(&other.bytes)
434 }
435}
436
437impl Hash for Decimal {
438 fn hash<H: Hasher>(&self, state: &mut H) {
439 self.bytes.hash(state);
440 }
441}
442
443impl Serialize for Decimal {
444 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
445 where
446 S: Serializer,
447 {
448 serializer.serialize_str(&self.to_string())
450 }
451}
452
453impl<'de> Deserialize<'de> for Decimal {
454 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
455 where
456 D: Deserializer<'de>,
457 {
458 let s = String::deserialize(deserializer)?;
459 Decimal::from_str(&s).map_err(serde::de::Error::custom)
460 }
461}
462
463macro_rules! impl_from_int {
465 ($($t:ty),*) => {
466 $(
467 impl From<$t> for Decimal {
468 fn from(val: $t) -> Self {
469 Decimal::from_str(&val.to_string()).expect("Integer is always valid")
473 }
474 }
475 )*
476 };
477}
478
479impl_from_int!(i8, i16, i32, i64, i128, u8, u16, u32, u64, u128);
480
481impl TryFrom<f64> for Decimal {
482 type Error = DecimalError;
483
484 fn try_from(val: f64) -> Result<Self, Self::Error> {
510 if val.is_nan() {
511 return Ok(Decimal::nan());
512 }
513 if val.is_infinite() {
514 return Ok(if val.is_sign_positive() {
515 Decimal::infinity()
516 } else {
517 Decimal::neg_infinity()
518 });
519 }
520 Decimal::from_str(&val.to_string())
521 }
522}
523
524impl Default for Decimal {
525 fn default() -> Self {
526 Decimal {
527 bytes: vec![encoding::SIGN_ZERO],
528 }
529 }
530}
531
532#[cfg(feature = "rust_decimal")]
537mod rust_decimal_interop {
538 use super::{Decimal, DecimalError};
539 use std::str::FromStr;
540
541 impl TryFrom<rust_decimal::Decimal> for Decimal {
542 type Error = DecimalError;
543
544 fn try_from(value: rust_decimal::Decimal) -> Result<Self, Self::Error> {
557 Decimal::from_str(&value.to_string())
558 }
559 }
560
561 impl TryFrom<&Decimal> for rust_decimal::Decimal {
562 type Error = rust_decimal::Error;
563
564 fn try_from(value: &Decimal) -> Result<Self, Self::Error> {
580 use std::str::FromStr;
581 rust_decimal::Decimal::from_str(&value.to_string())
582 }
583 }
584
585 impl TryFrom<Decimal> for rust_decimal::Decimal {
586 type Error = rust_decimal::Error;
587
588 fn try_from(value: Decimal) -> Result<Self, Self::Error> {
589 rust_decimal::Decimal::try_from(&value)
590 }
591 }
592}
593
594#[cfg(feature = "bigdecimal")]
602mod bigdecimal_interop {
603 use super::{Decimal, DecimalError};
604 use std::str::FromStr;
605
606 impl TryFrom<bigdecimal::BigDecimal> for Decimal {
607 type Error = DecimalError;
608
609 fn try_from(value: bigdecimal::BigDecimal) -> Result<Self, Self::Error> {
611 Decimal::from_str(&value.to_string())
612 }
613 }
614
615 impl TryFrom<&bigdecimal::BigDecimal> for Decimal {
616 type Error = DecimalError;
617
618 fn try_from(value: &bigdecimal::BigDecimal) -> Result<Self, Self::Error> {
619 Decimal::from_str(&value.to_string())
620 }
621 }
622
623 impl TryFrom<&Decimal> for bigdecimal::BigDecimal {
624 type Error = bigdecimal::ParseBigDecimalError;
625
626 fn try_from(value: &Decimal) -> Result<Self, Self::Error> {
631 use std::str::FromStr;
632 bigdecimal::BigDecimal::from_str(&value.to_string())
633 }
634 }
635
636 impl TryFrom<Decimal> for bigdecimal::BigDecimal {
637 type Error = bigdecimal::ParseBigDecimalError;
638
639 fn try_from(value: Decimal) -> Result<Self, Self::Error> {
640 bigdecimal::BigDecimal::try_from(&value)
641 }
642 }
643}
644
645#[cfg(test)]
649mod tests {
650 use super::*;
651
652 #[test]
653 fn test_from_str() {
654 let d = Decimal::from_str("123.456").unwrap();
655 assert_eq!(d.to_string(), "123.456");
656 }
657
658 #[test]
659 fn test_zero() {
660 let d = Decimal::from_str("0").unwrap();
661 assert!(d.is_zero());
662 assert!(!d.is_negative());
663 assert!(!d.is_positive());
664 assert!(d.is_finite());
665 assert!(!d.is_special());
666 }
667
668 #[test]
669 fn test_negative() {
670 let d = Decimal::from_str("-123.456").unwrap();
671 assert!(d.is_negative());
672 assert!(!d.is_zero());
673 assert!(!d.is_positive());
674 assert!(d.is_finite());
675 }
676
677 #[test]
678 fn test_positive() {
679 let d = Decimal::from_str("123.456").unwrap();
680 assert!(d.is_positive());
681 assert!(!d.is_zero());
682 assert!(!d.is_negative());
683 assert!(d.is_finite());
684 }
685
686 #[test]
687 fn test_ordering() {
688 let values = vec!["-100", "-10", "-1", "-0.1", "0", "0.1", "1", "10", "100"];
689 let decimals: Vec<Decimal> = values
690 .iter()
691 .map(|s| Decimal::from_str(s).unwrap())
692 .collect();
693
694 for i in 0..decimals.len() - 1 {
696 assert!(
697 decimals[i] < decimals[i + 1],
698 "{} should be < {}",
699 values[i],
700 values[i + 1]
701 );
702 }
703
704 for i in 0..decimals.len() - 1 {
706 assert!(
707 decimals[i].as_bytes() < decimals[i + 1].as_bytes(),
708 "bytes of {} should be < bytes of {}",
709 values[i],
710 values[i + 1]
711 );
712 }
713 }
714
715 #[test]
716 fn test_roundtrip() {
717 let values = vec![
718 "0", "1", "-1", "123.456", "-123.456", "0.001", "0.1", "10", "100", "1000000",
719 "-1000000",
720 ];
721
722 for s in values {
723 let d = Decimal::from_str(s).unwrap();
724 let bytes = d.as_bytes();
725 let restored = Decimal::from_bytes(bytes).unwrap();
726 assert_eq!(d, restored, "Roundtrip failed for {}", s);
727 }
728 }
729
730 #[test]
731 fn test_precision_scale() {
732 let d = Decimal::with_precision_scale("123.456", Some(10), Some(2)).unwrap();
734 assert_eq!(d.to_string(), "123.46");
735
736 let d = Decimal::with_precision_scale("12345.67", Some(5), Some(2)).unwrap();
738 assert_eq!(d.to_string(), "345.67"); let d = Decimal::with_precision_scale("99.999", Some(5), Some(2)).unwrap();
742 assert_eq!(d.to_string(), "100"); }
744
745 #[test]
746 fn test_from_integer() {
747 let d = Decimal::from(42i64);
748 assert_eq!(d.to_string(), "42");
749
750 let d = Decimal::from(-100i32);
751 assert_eq!(d.to_string(), "-100");
752 }
753
754 #[test]
755 fn test_from_f64() {
756 let d: Decimal = 123.456f64.try_into().unwrap();
758 assert_eq!(d.to_string(), "123.456");
759
760 let d: Decimal = (-99.5f64).try_into().unwrap();
761 assert_eq!(d.to_string(), "-99.5");
762
763 let d: Decimal = 0.0f64.try_into().unwrap();
764 assert!(d.is_zero());
765
766 let inf: Decimal = f64::INFINITY.try_into().unwrap();
768 assert!(inf.is_pos_infinity());
769
770 let neg_inf: Decimal = f64::NEG_INFINITY.try_into().unwrap();
771 assert!(neg_inf.is_neg_infinity());
772
773 let nan: Decimal = f64::NAN.try_into().unwrap();
774 assert!(nan.is_nan());
775 }
776
777 #[test]
778 fn test_serialization() {
779 let d = Decimal::from_str("123.456").unwrap();
780 let json = serde_json::to_string(&d).unwrap();
781 assert_eq!(json, "\"123.456\"");
782
783 let restored: Decimal = serde_json::from_str(&json).unwrap();
784 assert_eq!(d, restored);
785 }
786
787 #[test]
788 fn test_byte_efficiency() {
789 let d = Decimal::from_str("123456789").unwrap();
791 assert!(
793 d.byte_len() <= 10,
794 "Expected <= 10 bytes, got {}",
795 d.byte_len()
796 );
797
798 let d = Decimal::from_str("0.000001").unwrap();
799 assert!(
801 d.byte_len() <= 6,
802 "Expected <= 6 bytes, got {}",
803 d.byte_len()
804 );
805 }
806
807 #[test]
810 fn test_infinity_creation() {
811 let pos_inf = Decimal::infinity();
812 assert!(pos_inf.is_pos_infinity());
813 assert!(pos_inf.is_infinity());
814 assert!(!pos_inf.is_neg_infinity());
815 assert!(!pos_inf.is_nan());
816 assert!(pos_inf.is_special());
817 assert!(!pos_inf.is_finite());
818 assert_eq!(pos_inf.to_string(), "Infinity");
819
820 let neg_inf = Decimal::neg_infinity();
821 assert!(neg_inf.is_neg_infinity());
822 assert!(neg_inf.is_infinity());
823 assert!(!neg_inf.is_pos_infinity());
824 assert!(!neg_inf.is_nan());
825 assert!(neg_inf.is_special());
826 assert!(!neg_inf.is_finite());
827 assert_eq!(neg_inf.to_string(), "-Infinity");
828 }
829
830 #[test]
831 fn test_nan_creation() {
832 let nan = Decimal::nan();
833 assert!(nan.is_nan());
834 assert!(nan.is_special());
835 assert!(!nan.is_finite());
836 assert!(!nan.is_infinity());
837 assert!(!nan.is_zero());
838 assert_eq!(nan.to_string(), "NaN");
839 }
840
841 #[test]
842 fn test_special_value_from_str() {
843 let pos_inf = Decimal::from_str("Infinity").unwrap();
844 assert!(pos_inf.is_pos_infinity());
845
846 let neg_inf = Decimal::from_str("-Infinity").unwrap();
847 assert!(neg_inf.is_neg_infinity());
848
849 let nan = Decimal::from_str("NaN").unwrap();
850 assert!(nan.is_nan());
851
852 let inf = Decimal::from_str("infinity").unwrap();
854 assert!(inf.is_pos_infinity());
855
856 let inf = Decimal::from_str("INF").unwrap();
857 assert!(inf.is_pos_infinity());
858 }
859
860 #[test]
861 fn test_special_value_ordering() {
862 let neg_inf = Decimal::neg_infinity();
864 let neg_num = Decimal::from_str("-1000").unwrap();
865 let zero = Decimal::from_str("0").unwrap();
866 let pos_num = Decimal::from_str("1000").unwrap();
867 let pos_inf = Decimal::infinity();
868 let nan = Decimal::nan();
869
870 assert!(neg_inf < neg_num);
871 assert!(neg_num < zero);
872 assert!(zero < pos_num);
873 assert!(pos_num < pos_inf);
874 assert!(pos_inf < nan);
875
876 assert!(neg_inf.as_bytes() < neg_num.as_bytes());
878 assert!(neg_num.as_bytes() < zero.as_bytes());
879 assert!(zero.as_bytes() < pos_num.as_bytes());
880 assert!(pos_num.as_bytes() < pos_inf.as_bytes());
881 assert!(pos_inf.as_bytes() < nan.as_bytes());
882 }
883
884 #[test]
885 fn test_special_value_equality() {
886 let nan1 = Decimal::from_str("NaN").unwrap();
888 let nan2 = Decimal::from_str("nan").unwrap();
889 let nan3 = Decimal::nan();
890 assert_eq!(nan1, nan2);
891 assert_eq!(nan2, nan3);
892
893 let inf1 = Decimal::infinity();
895 let inf2 = Decimal::from_str("Infinity").unwrap();
896 assert_eq!(inf1, inf2);
897
898 let neg_inf1 = Decimal::neg_infinity();
899 let neg_inf2 = Decimal::from_str("-Infinity").unwrap();
900 assert_eq!(neg_inf1, neg_inf2);
901 }
902
903 #[test]
904 fn test_special_value_serialization() {
905 let inf = Decimal::infinity();
906 let json = serde_json::to_string(&inf).unwrap();
907 assert_eq!(json, "\"Infinity\"");
908 let restored: Decimal = serde_json::from_str(&json).unwrap();
909 assert_eq!(inf, restored);
910
911 let nan = Decimal::nan();
912 let json = serde_json::to_string(&nan).unwrap();
913 assert_eq!(json, "\"NaN\"");
914 let restored: Decimal = serde_json::from_str(&json).unwrap();
915 assert_eq!(nan, restored);
916 }
917
918 #[test]
919 fn test_special_value_byte_efficiency() {
920 assert_eq!(Decimal::infinity().byte_len(), 3);
922 assert_eq!(Decimal::neg_infinity().byte_len(), 3);
923 assert_eq!(Decimal::nan().byte_len(), 3);
924 }
925
926 #[test]
929 fn test_negative_scale() {
930 let d = Decimal::with_precision_scale("12345", Some(10), Some(-3)).unwrap();
932 assert_eq!(d.to_string(), "12000");
933
934 let d = Decimal::with_precision_scale("12500", Some(10), Some(-3)).unwrap();
936 assert_eq!(d.to_string(), "13000");
937
938 let d = Decimal::with_precision_scale("1234", Some(10), Some(-2)).unwrap();
940 assert_eq!(d.to_string(), "1200");
941 }
942
943 #[test]
944 fn test_negative_scale_with_precision() {
945 let d = Decimal::with_precision_scale("12345", Some(2), Some(-3)).unwrap();
947 assert_eq!(d.to_string(), "12000");
948 }
949
950 #[test]
953 fn test_invalid_format_errors() {
954 let result = Decimal::from_str("1.2.3");
956 assert!(result.is_err());
957 assert!(matches!(
958 result.unwrap_err(),
959 DecimalError::InvalidFormat(_)
960 ));
961
962 let result = Decimal::from_str("12abc");
964 assert!(result.is_err());
965
966 let result = Decimal::from_str("1e");
968 assert!(result.is_err());
969 assert!(matches!(
970 result.unwrap_err(),
971 DecimalError::InvalidFormat(_)
972 ));
973
974 let result = Decimal::from_str("1eabc");
976 assert!(result.is_err());
977
978 let d = Decimal::from_str("").unwrap();
980 assert!(d.is_zero());
981
982 let result = Decimal::from_str("-");
984 assert!(result.is_ok()); }
986
987 #[test]
988 fn test_leading_plus_sign() {
989 let d = Decimal::from_str("+123.456").unwrap();
990 assert_eq!(d.to_string(), "123.456");
991 assert!(d.is_positive());
992 }
993
994 #[test]
995 fn test_scientific_notation() {
996 let d = Decimal::from_str("1.5e10").unwrap();
997 assert_eq!(d.to_string(), "15000000000");
998
999 let d = Decimal::from_str("1.5E-3").unwrap();
1000 assert_eq!(d.to_string(), "0.0015");
1001
1002 let d = Decimal::from_str("1e+5").unwrap();
1003 assert_eq!(d.to_string(), "100000");
1004 }
1005
1006 #[test]
1007 fn test_leading_decimal_point() {
1008 let d = Decimal::from_str(".5").unwrap();
1010 assert_eq!(d.to_string(), "0.5");
1011
1012 let d = Decimal::from_str("-.25").unwrap();
1013 assert_eq!(d.to_string(), "-0.25");
1014 }
1015
1016 #[test]
1017 fn test_trailing_zeros() {
1018 let d = Decimal::from_str("100").unwrap();
1019 assert_eq!(d.to_string(), "100");
1020
1021 let d = Decimal::from_str("1.500").unwrap();
1022 assert_eq!(d.to_string(), "1.5");
1023 }
1024
1025 #[test]
1026 fn test_leading_zeros() {
1027 let d = Decimal::from_str("007").unwrap();
1028 assert_eq!(d.to_string(), "7");
1029
1030 let d = Decimal::from_str("00.123").unwrap();
1031 assert_eq!(d.to_string(), "0.123");
1032 }
1033
1034 #[test]
1037 fn test_into_bytes() {
1038 let d = Decimal::from_str("123.456").unwrap();
1039 let bytes_ref = d.as_bytes().to_vec();
1040 let bytes_owned = d.into_bytes();
1041 assert_eq!(bytes_ref, bytes_owned);
1042 }
1043
1044 #[test]
1045 fn test_clone() {
1046 let d1 = Decimal::from_str("123.456").unwrap();
1047 let d2 = d1.clone();
1048 assert_eq!(d1, d2);
1049 assert_eq!(d1.as_bytes(), d2.as_bytes());
1050 }
1051
1052 #[test]
1053 fn test_hash() {
1054 use std::collections::HashSet;
1055
1056 let mut set = HashSet::new();
1057 set.insert(Decimal::from_str("123.456").unwrap());
1058 set.insert(Decimal::from_str("123.456").unwrap()); set.insert(Decimal::from_str("789.012").unwrap());
1060
1061 assert_eq!(set.len(), 2);
1062 assert!(set.contains(&Decimal::from_str("123.456").unwrap()));
1063 }
1064
1065 #[test]
1066 fn test_debug_format() {
1067 let d = Decimal::from_str("123.456").unwrap();
1068 let debug_str = format!("{:?}", d);
1069 assert!(debug_str.contains("Decimal"));
1070 assert!(debug_str.contains("123.456"));
1071 }
1072
1073 #[test]
1074 fn test_ord_trait() {
1075 use std::cmp::Ordering;
1076
1077 let a = Decimal::from_str("1").unwrap();
1078 let b = Decimal::from_str("2").unwrap();
1079 let c = Decimal::from_str("1").unwrap();
1080
1081 assert_eq!(a.cmp(&b), Ordering::Less);
1082 assert_eq!(b.cmp(&a), Ordering::Greater);
1083 assert_eq!(a.cmp(&c), Ordering::Equal);
1084 }
1085
1086 #[test]
1087 fn test_from_bytes_invalid() {
1088 let result = Decimal::from_bytes(&[]);
1090 assert!(result.is_err());
1091
1092 let result = Decimal::from_bytes(&[0x00]);
1094 assert!(result.is_err());
1095 }
1096
1097 #[test]
1098 fn test_deserialize_from_string_number() {
1099 let d: Decimal = serde_json::from_str("\"42\"").unwrap();
1101 assert_eq!(d.to_string(), "42");
1102
1103 let d: Decimal = serde_json::from_str("\"-100\"").unwrap();
1104 assert_eq!(d.to_string(), "-100");
1105
1106 let d: Decimal = serde_json::from_str("\"1.5e10\"").unwrap();
1107 assert_eq!(d.to_string(), "15000000000");
1108 }
1109
1110 #[test]
1111 fn test_from_various_integer_types() {
1112 assert_eq!(Decimal::from(0i32).to_string(), "0");
1113 assert_eq!(Decimal::from(i32::MAX).to_string(), "2147483647");
1114 assert_eq!(Decimal::from(i32::MIN).to_string(), "-2147483648");
1115 assert_eq!(Decimal::from(i64::MAX).to_string(), "9223372036854775807");
1116 assert_eq!(Decimal::from(i64::MIN).to_string(), "-9223372036854775808");
1117 }
1118
1119 #[test]
1120 fn test_precision_overflow() {
1121 let result = Decimal::from_str("1e20000");
1123 assert!(result.is_err());
1124 assert!(matches!(
1125 result.unwrap_err(),
1126 DecimalError::PrecisionOverflow
1127 ));
1128
1129 let result = Decimal::from_str("1e-20000");
1131 assert!(result.is_err());
1132 assert!(matches!(
1133 result.unwrap_err(),
1134 DecimalError::PrecisionOverflow
1135 ));
1136 }
1137
1138 #[test]
1139 fn test_all_zeros_variations() {
1140 let d = Decimal::from_str("0").unwrap();
1141 assert!(d.is_zero());
1142
1143 let d = Decimal::from_str("0.0").unwrap();
1144 assert!(d.is_zero());
1145
1146 let d = Decimal::from_str("00.00").unwrap();
1147 assert!(d.is_zero());
1148
1149 let d = Decimal::from_str("-0").unwrap();
1150 assert!(d.is_zero());
1151 }
1153
1154 #[test]
1157 fn test_rounding_all_nines() {
1158 let d = Decimal::with_precision_scale("99.999", Some(10), Some(2)).unwrap();
1160 assert_eq!(d.to_string(), "100");
1161
1162 let d = Decimal::with_precision_scale("9.99", Some(10), Some(1)).unwrap();
1164 assert_eq!(d.to_string(), "10");
1165
1166 let d = Decimal::with_precision_scale("999", Some(10), Some(-1)).unwrap();
1168 assert_eq!(d.to_string(), "1000");
1169 }
1170
1171 #[test]
1172 fn test_negative_scale_small_number() {
1173 let d = Decimal::with_precision_scale("4", Some(10), Some(-1)).unwrap();
1175 assert_eq!(d.to_string(), "0");
1176
1177 let d = Decimal::with_precision_scale("5", Some(10), Some(-1)).unwrap();
1179 assert_eq!(d.to_string(), "10");
1180
1181 let d = Decimal::with_precision_scale("-4", Some(10), Some(-1)).unwrap();
1183 assert_eq!(d.to_string(), "0");
1184
1185 let d = Decimal::with_precision_scale("-5", Some(10), Some(-1)).unwrap();
1187 assert_eq!(d.to_string(), "-10");
1188 }
1189
1190 #[test]
1191 fn test_precision_truncation() {
1192 let d = Decimal::with_precision_scale("123456", Some(3), Some(0)).unwrap();
1194 assert_eq!(d.to_string(), "456");
1195
1196 let d = Decimal::with_precision_scale("12345.67", Some(4), Some(2)).unwrap();
1198 assert_eq!(d.to_string(), "45.67");
1199 }
1200
1201 #[test]
1202 fn test_very_small_numbers() {
1203 let d = Decimal::from_str("0.000000001").unwrap();
1204 assert_eq!(d.to_string(), "0.000000001");
1205 assert!(d.is_positive());
1206
1207 let d = Decimal::from_str("-0.000000001").unwrap();
1208 assert_eq!(d.to_string(), "-0.000000001");
1209 assert!(d.is_negative());
1210 }
1211
1212 #[test]
1213 fn test_very_large_numbers() {
1214 let d = Decimal::from_str("999999999999999999999999999999").unwrap();
1215 assert_eq!(d.to_string(), "999999999999999999999999999999");
1216
1217 let d = Decimal::from_str("-999999999999999999999999999999").unwrap();
1218 assert_eq!(d.to_string(), "-999999999999999999999999999999");
1219 }
1220
1221 #[test]
1222 fn test_max_exponent_boundary() {
1223 let d = Decimal::from_str("1e16000").unwrap();
1225 assert!(d.is_positive());
1226
1227 let result = Decimal::from_str("1e17000");
1229 assert!(result.is_err());
1230 }
1231
1232 #[test]
1233 fn test_min_exponent_boundary() {
1234 let d = Decimal::from_str("1e-16000").unwrap();
1236 assert!(d.is_positive());
1237
1238 let result = Decimal::from_str("1e-17000");
1240 assert!(result.is_err());
1241 }
1242
1243 #[test]
1244 fn test_odd_digit_count() {
1245 let d = Decimal::from_str("12345").unwrap();
1247 assert_eq!(d.to_string(), "12345");
1248
1249 let d = Decimal::from_str("1").unwrap();
1250 assert_eq!(d.to_string(), "1");
1251
1252 let d = Decimal::from_str("123").unwrap();
1253 assert_eq!(d.to_string(), "123");
1254 }
1255
1256 #[test]
1257 fn test_negative_number_ordering() {
1258 let a = Decimal::from_str("-100").unwrap();
1260 let b = Decimal::from_str("-10").unwrap();
1261 let c = Decimal::from_str("-1").unwrap();
1262
1263 assert!(a < b);
1265 assert!(b < c);
1266
1267 assert!(a.as_bytes() < b.as_bytes());
1269 assert!(b.as_bytes() < c.as_bytes());
1270 }
1271
1272 #[test]
1273 fn test_from_bytes_unchecked_roundtrip() {
1274 let original = Decimal::from_str("123.456").unwrap();
1275 let bytes = original.as_bytes().to_vec();
1276 let restored = Decimal::from_bytes_unchecked(bytes);
1277 assert_eq!(original, restored);
1278 }
1279
1280 #[test]
1281 fn test_special_value_checks() {
1282 let d = Decimal::from_str("123.456").unwrap();
1283 assert!(!d.is_nan());
1284 assert!(!d.is_infinity());
1285 assert!(!d.is_pos_infinity());
1286 assert!(!d.is_neg_infinity());
1287 assert!(!d.is_special());
1288 assert!(d.is_finite());
1289 }
1290
1291 #[test]
1292 fn test_equality_and_hash_consistency() {
1293 use std::collections::HashMap;
1294
1295 let d1 = Decimal::from_str("123.456").unwrap();
1296 let d2 = Decimal::from_str("123.456").unwrap();
1297 let d3 = Decimal::from_str("123.457").unwrap();
1298
1299 assert_eq!(d1, d2);
1301 assert_ne!(d1, d3);
1302
1303 let mut map = HashMap::new();
1305 map.insert(d1.clone(), "first");
1306 map.insert(d2.clone(), "second"); assert_eq!(map.len(), 1);
1308 assert_eq!(map.get(&d1), Some(&"second"));
1309 }
1310
1311 #[test]
1312 fn test_scale_zero() {
1313 let d = Decimal::with_precision_scale("123.999", Some(10), Some(0)).unwrap();
1315 assert_eq!(d.to_string(), "124"); }
1317
1318 #[test]
1319 fn test_only_fractional_with_precision_scale() {
1320 let d = Decimal::with_precision_scale(".5", Some(10), Some(2)).unwrap();
1321 assert_eq!(d.to_string(), "0.5");
1322 }
1323
1324 #[test]
1325 fn test_default_impl() {
1326 let d = Decimal::default();
1327 assert!(d.is_zero());
1328 assert_eq!(d.to_string(), "0");
1329 }
1330
1331 #[test]
1332 fn test_precision_zero_integer_digits() {
1333 let d = Decimal::with_precision_scale("123.456", Some(2), Some(2)).unwrap();
1336 assert_eq!(d.to_string(), "0.46");
1337 }
1338
1339 #[test]
1340 fn test_negative_with_precision_truncation() {
1341 let d = Decimal::with_precision_scale("-123.456", Some(3), Some(2)).unwrap();
1343 assert_eq!(d.to_string(), "-3.46");
1344 }
1345
1346 #[test]
1347 fn test_invalid_sign_byte() {
1348 let result = Decimal::from_bytes(&[0x01, 0x40, 0x00, 0x12]);
1353 assert!(result.is_err());
1354
1355 let result = Decimal::from_bytes(&[0x7F, 0x40, 0x00, 0x12]);
1357 assert!(result.is_err());
1358
1359 let result = Decimal::from_bytes(&[0xFE, 0x40, 0x00, 0x12]);
1361 assert!(result.is_err());
1362 }
1363
1364 #[test]
1365 fn test_invalid_bcd_encoding() {
1366 let invalid_bytes = vec![
1370 0xFF, 0x80, 0x00, 0xAB, ];
1374 let result = Decimal::from_bytes(&invalid_bytes);
1375 assert!(result.is_err());
1376
1377 let invalid_bytes = vec![
1379 0xFF, 0x80, 0x00, 0xA1, ];
1383 let result = Decimal::from_bytes(&invalid_bytes);
1384 assert!(result.is_err());
1385
1386 let invalid_bytes = vec![
1388 0xFF, 0x80, 0x00, 0x1B, ];
1392 let result = Decimal::from_bytes(&invalid_bytes);
1393 assert!(result.is_err());
1394 }
1395
1396 #[test]
1397 fn test_reserved_exponent_positive() {
1398 let bytes_with_reserved_exp = vec![
1405 0xFF, 0xFF, 0xFF, 0x12, ];
1409 let result = Decimal::from_bytes(&bytes_with_reserved_exp);
1410 assert!(result.is_err());
1411
1412 let bytes_with_reserved_exp = vec![
1414 0xFF, 0xFF, 0xFE, 0x12, ];
1418 let result = Decimal::from_bytes(&bytes_with_reserved_exp);
1419 assert!(result.is_err());
1420 }
1421
1422 #[test]
1423 fn test_reserved_exponent_negative() {
1424 let bytes_with_reserved_exp = vec![
1429 0x00, 0x00, 0x00, 0x12, ];
1433 let result = Decimal::from_bytes(&bytes_with_reserved_exp);
1434 assert!(result.is_err());
1435 }
1436
1437 #[test]
1438 fn test_empty_mantissa_bytes() {
1439 let bytes_no_mantissa = vec![
1442 0xFF, 0x80, 0x00, ];
1446 let d = Decimal::from_bytes(&bytes_no_mantissa).unwrap();
1447 assert_eq!(d.to_string(), "0");
1448 }
1449
1450 #[cfg(feature = "rust_decimal")]
1453 mod rust_decimal_tests {
1454 use super::*;
1455
1456 #[test]
1457 fn test_from_rust_decimal() {
1458 use rust_decimal::Decimal as RustDecimal;
1459
1460 let rd = RustDecimal::new(12345, 2); let d: Decimal = rd.try_into().unwrap();
1462 assert_eq!(d.to_string(), "123.45");
1463 }
1464
1465 #[test]
1466 fn test_to_rust_decimal() {
1467 use rust_decimal::Decimal as RustDecimal;
1468
1469 let d = Decimal::from_str("123.45").unwrap();
1470 let rd: RustDecimal = (&d).try_into().unwrap();
1471 assert_eq!(rd.to_string(), "123.45");
1472 }
1473
1474 #[test]
1475 fn test_rust_decimal_roundtrip() {
1476 use rust_decimal::Decimal as RustDecimal;
1477
1478 let values = vec!["0", "1", "-1", "123.456", "-999.999", "0.001"];
1479
1480 for s in values {
1481 let d = Decimal::from_str(s).unwrap();
1482 let rd: RustDecimal = (&d).try_into().unwrap();
1483 let d2: Decimal = rd.try_into().unwrap();
1484 assert_eq!(d, d2, "Roundtrip failed for {}", s);
1485 }
1486 }
1487
1488 #[test]
1489 fn test_rust_decimal_arithmetic() {
1490 use rust_decimal::Decimal as RustDecimal;
1491
1492 let a = Decimal::from_str("100.50").unwrap();
1494 let b = Decimal::from_str("25.25").unwrap();
1495
1496 let ra: RustDecimal = (&a).try_into().unwrap();
1498 let rb: RustDecimal = (&b).try_into().unwrap();
1499 let sum = ra + rb;
1500
1501 let result: Decimal = sum.try_into().unwrap();
1503 assert_eq!(result.to_string(), "125.75");
1504 }
1505
1506 #[test]
1507 fn test_rust_decimal_from_owned() {
1508 use rust_decimal::Decimal as RustDecimal;
1509
1510 let d = Decimal::from_str("456.789").unwrap();
1512 let rd: RustDecimal = d.try_into().unwrap();
1513 assert_eq!(rd.to_string(), "456.789");
1514 }
1515
1516 #[test]
1517 fn test_rust_decimal_special_values_fail() {
1518 use rust_decimal::Decimal as RustDecimal;
1519
1520 let inf = Decimal::infinity();
1522 let result: Result<RustDecimal, _> = (&inf).try_into();
1523 assert!(result.is_err());
1524
1525 let nan = Decimal::nan();
1527 let result: Result<RustDecimal, _> = (&nan).try_into();
1528 assert!(result.is_err());
1529 }
1530 }
1531
1532 #[cfg(feature = "bigdecimal")]
1535 mod bigdecimal_tests {
1536 use super::*;
1537
1538 #[test]
1539 fn test_from_bigdecimal() {
1540 use bigdecimal::BigDecimal;
1541 use std::str::FromStr;
1542
1543 let bd = BigDecimal::from_str("123.45").unwrap();
1544 let d: Decimal = bd.try_into().unwrap();
1545 assert_eq!(d.to_string(), "123.45");
1546 }
1547
1548 #[test]
1549 fn test_to_bigdecimal() {
1550 use bigdecimal::BigDecimal;
1551
1552 let d = Decimal::from_str("123.45").unwrap();
1553 let bd: BigDecimal = (&d).try_into().unwrap();
1554 assert_eq!(bd.to_string(), "123.45");
1555 }
1556
1557 #[test]
1558 fn test_bigdecimal_roundtrip() {
1559 use bigdecimal::BigDecimal;
1560
1561 let values = vec!["0", "1", "-1", "123.456", "-999.999", "0.001"];
1562
1563 for s in values {
1564 let d = Decimal::from_str(s).unwrap();
1565 let bd: BigDecimal = (&d).try_into().unwrap();
1566 let d2: Decimal = bd.try_into().unwrap();
1567 assert_eq!(d, d2, "Roundtrip failed for {}", s);
1568 }
1569 }
1570
1571 #[test]
1572 fn test_bigdecimal_from_owned() {
1573 use bigdecimal::BigDecimal;
1574
1575 let d = Decimal::from_str("456.789").unwrap();
1577 let bd: BigDecimal = d.try_into().unwrap();
1578 assert_eq!(bd.to_string(), "456.789");
1579 }
1580
1581 #[test]
1582 fn test_bigdecimal_from_ref() {
1583 use bigdecimal::BigDecimal;
1584 use std::str::FromStr;
1585
1586 let bd = BigDecimal::from_str("789.012").unwrap();
1588 let d: Decimal = (&bd).try_into().unwrap();
1589 assert_eq!(d.to_string(), "789.012");
1590 }
1591
1592 #[test]
1593 fn test_bigdecimal_special_values_fail() {
1594 use bigdecimal::BigDecimal;
1595
1596 let inf = Decimal::infinity();
1598 let result: Result<BigDecimal, _> = (&inf).try_into();
1599 assert!(result.is_err());
1600
1601 let nan = Decimal::nan();
1603 let result: Result<BigDecimal, _> = (&nan).try_into();
1604 assert!(result.is_err());
1605 }
1606 }
1607}