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, decode_to_string_with_scale, encode_decimal,
139 encode_decimal_with_constraints, encode_special_value, ENCODING_NAN, ENCODING_NEG_INFINITY,
140 ENCODING_POS_INFINITY,
141};
142
143#[derive(Clone)]
156pub struct Decimal {
157 bytes: Vec<u8>,
158}
159
160impl Decimal {
161 pub fn with_precision_scale(
189 s: &str,
190 precision: Option<u32>,
191 scale: Option<i32>,
192 ) -> Result<Self, DecimalError> {
193 let bytes = encode_decimal_with_constraints(s, precision, scale)?;
194 Ok(Self { bytes })
195 }
196
197 pub fn from_bytes(bytes: &[u8]) -> Result<Self, DecimalError> {
214 let _ = decode_to_string(bytes)?;
216 Ok(Self {
217 bytes: bytes.to_vec(),
218 })
219 }
220
221 #[inline]
228 pub fn from_bytes_unchecked(bytes: Vec<u8>) -> Self {
229 Self { bytes }
230 }
231
232 #[inline]
237 pub fn as_bytes(&self) -> &[u8] {
238 &self.bytes
239 }
240
241 #[inline]
243 pub fn into_bytes(self) -> Vec<u8> {
244 self.bytes
245 }
246
247 pub fn is_zero(&self) -> bool {
249 self.bytes.len() == 1 && self.bytes[0] == encoding::SIGN_ZERO
250 }
251
252 pub fn is_negative(&self) -> bool {
254 !self.bytes.is_empty() && self.bytes[0] == encoding::SIGN_NEGATIVE
255 }
256
257 pub fn is_positive(&self) -> bool {
259 !self.bytes.is_empty() && self.bytes[0] == encoding::SIGN_POSITIVE
260 }
261
262 pub fn is_pos_infinity(&self) -> bool {
264 self.bytes.as_slice() == ENCODING_POS_INFINITY
265 }
266
267 pub fn is_neg_infinity(&self) -> bool {
269 self.bytes.as_slice() == ENCODING_NEG_INFINITY
270 }
271
272 pub fn is_infinity(&self) -> bool {
274 self.is_pos_infinity() || self.is_neg_infinity()
275 }
276
277 pub fn is_nan(&self) -> bool {
279 self.bytes.as_slice() == ENCODING_NAN
280 }
281
282 pub fn is_special(&self) -> bool {
284 decode_special_value(&self.bytes).is_some()
285 }
286
287 pub fn is_finite(&self) -> bool {
289 !self.is_special()
290 }
291
292 #[inline]
294 pub fn byte_len(&self) -> usize {
295 self.bytes.len()
296 }
297
298 pub fn infinity() -> Self {
315 Self {
316 bytes: encode_special_value(SpecialValue::Infinity),
317 }
318 }
319
320 pub fn neg_infinity() -> Self {
337 Self {
338 bytes: encode_special_value(SpecialValue::NegInfinity),
339 }
340 }
341
342 pub fn nan() -> Self {
371 Self {
372 bytes: encode_special_value(SpecialValue::NaN),
373 }
374 }
375
376 pub fn to_string_with_scale(&self, scale: i32) -> String {
404 decode_to_string_with_scale(&self.bytes, scale).expect("Decimal contains valid bytes")
405 }
406}
407
408impl FromStr for Decimal {
409 type Err = DecimalError;
410
411 fn from_str(s: &str) -> Result<Self, Self::Err> {
426 let bytes = encode_decimal(s)?;
427 Ok(Self { bytes })
428 }
429}
430
431impl fmt::Display for Decimal {
432 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
433 let s = decode_to_string(&self.bytes).expect("Decimal contains valid bytes");
434 write!(f, "{}", s)
435 }
436}
437
438impl fmt::Debug for Decimal {
439 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
440 let value = decode_to_string(&self.bytes).expect("Decimal contains valid bytes");
441 f.debug_struct("Decimal")
442 .field("value", &value)
443 .field("bytes", &self.bytes)
444 .finish()
445 }
446}
447
448impl PartialEq for Decimal {
449 fn eq(&self, other: &Self) -> bool {
450 self.bytes == other.bytes
451 }
452}
453
454impl Eq for Decimal {}
455
456impl PartialOrd for Decimal {
457 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
458 Some(self.cmp(other))
459 }
460}
461
462impl Ord for Decimal {
463 fn cmp(&self, other: &Self) -> Ordering {
464 self.bytes.cmp(&other.bytes)
466 }
467}
468
469impl Hash for Decimal {
470 fn hash<H: Hasher>(&self, state: &mut H) {
471 self.bytes.hash(state);
472 }
473}
474
475impl Serialize for Decimal {
476 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
477 where
478 S: Serializer,
479 {
480 serializer.serialize_str(&self.to_string())
482 }
483}
484
485impl<'de> Deserialize<'de> for Decimal {
486 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
487 where
488 D: Deserializer<'de>,
489 {
490 let s = String::deserialize(deserializer)?;
491 Decimal::from_str(&s).map_err(serde::de::Error::custom)
492 }
493}
494
495macro_rules! impl_from_int {
497 ($($t:ty),*) => {
498 $(
499 impl From<$t> for Decimal {
500 fn from(val: $t) -> Self {
501 Decimal::from_str(&val.to_string()).expect("Integer is always valid")
505 }
506 }
507 )*
508 };
509}
510
511impl_from_int!(i8, i16, i32, i64, i128, u8, u16, u32, u64, u128);
512
513impl TryFrom<f64> for Decimal {
514 type Error = DecimalError;
515
516 fn try_from(val: f64) -> Result<Self, Self::Error> {
542 if val.is_nan() {
543 return Ok(Decimal::nan());
544 }
545 if val.is_infinite() {
546 return Ok(if val.is_sign_positive() {
547 Decimal::infinity()
548 } else {
549 Decimal::neg_infinity()
550 });
551 }
552 Decimal::from_str(&val.to_string())
553 }
554}
555
556impl Default for Decimal {
557 fn default() -> Self {
558 Decimal {
559 bytes: vec![encoding::SIGN_ZERO],
560 }
561 }
562}
563
564#[cfg(feature = "rust_decimal")]
569mod rust_decimal_interop {
570 use super::{Decimal, DecimalError};
571 use std::str::FromStr;
572
573 impl TryFrom<rust_decimal::Decimal> for Decimal {
574 type Error = DecimalError;
575
576 fn try_from(value: rust_decimal::Decimal) -> Result<Self, Self::Error> {
589 Decimal::from_str(&value.to_string())
590 }
591 }
592
593 impl TryFrom<&Decimal> for rust_decimal::Decimal {
594 type Error = rust_decimal::Error;
595
596 fn try_from(value: &Decimal) -> Result<Self, Self::Error> {
612 use std::str::FromStr;
613 rust_decimal::Decimal::from_str(&value.to_string())
614 }
615 }
616
617 impl TryFrom<Decimal> for rust_decimal::Decimal {
618 type Error = rust_decimal::Error;
619
620 fn try_from(value: Decimal) -> Result<Self, Self::Error> {
621 rust_decimal::Decimal::try_from(&value)
622 }
623 }
624}
625
626#[cfg(feature = "bigdecimal")]
634mod bigdecimal_interop {
635 use super::{Decimal, DecimalError};
636 use std::str::FromStr;
637
638 impl TryFrom<bigdecimal::BigDecimal> for Decimal {
639 type Error = DecimalError;
640
641 fn try_from(value: bigdecimal::BigDecimal) -> Result<Self, Self::Error> {
643 Decimal::from_str(&value.to_string())
644 }
645 }
646
647 impl TryFrom<&bigdecimal::BigDecimal> for Decimal {
648 type Error = DecimalError;
649
650 fn try_from(value: &bigdecimal::BigDecimal) -> Result<Self, Self::Error> {
651 Decimal::from_str(&value.to_string())
652 }
653 }
654
655 impl TryFrom<&Decimal> for bigdecimal::BigDecimal {
656 type Error = bigdecimal::ParseBigDecimalError;
657
658 fn try_from(value: &Decimal) -> Result<Self, Self::Error> {
663 use std::str::FromStr;
664 bigdecimal::BigDecimal::from_str(&value.to_string())
665 }
666 }
667
668 impl TryFrom<Decimal> for bigdecimal::BigDecimal {
669 type Error = bigdecimal::ParseBigDecimalError;
670
671 fn try_from(value: Decimal) -> Result<Self, Self::Error> {
672 bigdecimal::BigDecimal::try_from(&value)
673 }
674 }
675}
676
677#[cfg(test)]
681mod tests {
682 use super::*;
683
684 #[test]
685 fn test_from_str() {
686 let d = Decimal::from_str("123.456").unwrap();
687 assert_eq!(d.to_string(), "123.456");
688 }
689
690 #[test]
691 fn test_zero() {
692 let d = Decimal::from_str("0").unwrap();
693 assert!(d.is_zero());
694 assert!(!d.is_negative());
695 assert!(!d.is_positive());
696 assert!(d.is_finite());
697 assert!(!d.is_special());
698 }
699
700 #[test]
701 fn test_negative() {
702 let d = Decimal::from_str("-123.456").unwrap();
703 assert!(d.is_negative());
704 assert!(!d.is_zero());
705 assert!(!d.is_positive());
706 assert!(d.is_finite());
707 }
708
709 #[test]
710 fn test_positive() {
711 let d = Decimal::from_str("123.456").unwrap();
712 assert!(d.is_positive());
713 assert!(!d.is_zero());
714 assert!(!d.is_negative());
715 assert!(d.is_finite());
716 }
717
718 #[test]
719 fn test_ordering() {
720 let values = vec!["-100", "-10", "-1", "-0.1", "0", "0.1", "1", "10", "100"];
721 let decimals: Vec<Decimal> = values
722 .iter()
723 .map(|s| Decimal::from_str(s).unwrap())
724 .collect();
725
726 for i in 0..decimals.len() - 1 {
728 assert!(
729 decimals[i] < decimals[i + 1],
730 "{} should be < {}",
731 values[i],
732 values[i + 1]
733 );
734 }
735
736 for i in 0..decimals.len() - 1 {
738 assert!(
739 decimals[i].as_bytes() < decimals[i + 1].as_bytes(),
740 "bytes of {} should be < bytes of {}",
741 values[i],
742 values[i + 1]
743 );
744 }
745 }
746
747 #[test]
748 fn test_roundtrip() {
749 let values = vec![
750 "0", "1", "-1", "123.456", "-123.456", "0.001", "0.1", "10", "100", "1000000",
751 "-1000000",
752 ];
753
754 for s in values {
755 let d = Decimal::from_str(s).unwrap();
756 let bytes = d.as_bytes();
757 let restored = Decimal::from_bytes(bytes).unwrap();
758 assert_eq!(d, restored, "Roundtrip failed for {}", s);
759 }
760 }
761
762 #[test]
763 fn test_precision_scale() {
764 let d = Decimal::with_precision_scale("123.456", Some(10), Some(2)).unwrap();
766 assert_eq!(d.to_string(), "123.46");
767
768 let d = Decimal::with_precision_scale("12345.67", Some(5), Some(2)).unwrap();
770 assert_eq!(d.to_string(), "345.67"); let d = Decimal::with_precision_scale("99.999", Some(5), Some(2)).unwrap();
774 assert_eq!(d.to_string(), "100"); }
776
777 #[test]
778 fn test_from_integer() {
779 let d = Decimal::from(42i64);
780 assert_eq!(d.to_string(), "42");
781
782 let d = Decimal::from(-100i32);
783 assert_eq!(d.to_string(), "-100");
784 }
785
786 #[test]
787 fn test_from_f64() {
788 let d: Decimal = 123.456f64.try_into().unwrap();
790 assert_eq!(d.to_string(), "123.456");
791
792 let d: Decimal = (-99.5f64).try_into().unwrap();
793 assert_eq!(d.to_string(), "-99.5");
794
795 let d: Decimal = 0.0f64.try_into().unwrap();
796 assert!(d.is_zero());
797
798 let inf: Decimal = f64::INFINITY.try_into().unwrap();
800 assert!(inf.is_pos_infinity());
801
802 let neg_inf: Decimal = f64::NEG_INFINITY.try_into().unwrap();
803 assert!(neg_inf.is_neg_infinity());
804
805 let nan: Decimal = f64::NAN.try_into().unwrap();
806 assert!(nan.is_nan());
807 }
808
809 #[test]
810 fn test_serialization() {
811 let d = Decimal::from_str("123.456").unwrap();
812 let json = serde_json::to_string(&d).unwrap();
813 assert_eq!(json, "\"123.456\"");
814
815 let restored: Decimal = serde_json::from_str(&json).unwrap();
816 assert_eq!(d, restored);
817 }
818
819 #[test]
820 fn test_byte_efficiency() {
821 let d = Decimal::from_str("123456789").unwrap();
823 assert!(
825 d.byte_len() <= 10,
826 "Expected <= 10 bytes, got {}",
827 d.byte_len()
828 );
829
830 let d = Decimal::from_str("0.000001").unwrap();
831 assert!(
833 d.byte_len() <= 6,
834 "Expected <= 6 bytes, got {}",
835 d.byte_len()
836 );
837 }
838
839 #[test]
842 fn test_infinity_creation() {
843 let pos_inf = Decimal::infinity();
844 assert!(pos_inf.is_pos_infinity());
845 assert!(pos_inf.is_infinity());
846 assert!(!pos_inf.is_neg_infinity());
847 assert!(!pos_inf.is_nan());
848 assert!(pos_inf.is_special());
849 assert!(!pos_inf.is_finite());
850 assert_eq!(pos_inf.to_string(), "Infinity");
851
852 let neg_inf = Decimal::neg_infinity();
853 assert!(neg_inf.is_neg_infinity());
854 assert!(neg_inf.is_infinity());
855 assert!(!neg_inf.is_pos_infinity());
856 assert!(!neg_inf.is_nan());
857 assert!(neg_inf.is_special());
858 assert!(!neg_inf.is_finite());
859 assert_eq!(neg_inf.to_string(), "-Infinity");
860 }
861
862 #[test]
863 fn test_nan_creation() {
864 let nan = Decimal::nan();
865 assert!(nan.is_nan());
866 assert!(nan.is_special());
867 assert!(!nan.is_finite());
868 assert!(!nan.is_infinity());
869 assert!(!nan.is_zero());
870 assert_eq!(nan.to_string(), "NaN");
871 }
872
873 #[test]
874 fn test_special_value_from_str() {
875 let pos_inf = Decimal::from_str("Infinity").unwrap();
876 assert!(pos_inf.is_pos_infinity());
877
878 let neg_inf = Decimal::from_str("-Infinity").unwrap();
879 assert!(neg_inf.is_neg_infinity());
880
881 let nan = Decimal::from_str("NaN").unwrap();
882 assert!(nan.is_nan());
883
884 let inf = Decimal::from_str("infinity").unwrap();
886 assert!(inf.is_pos_infinity());
887
888 let inf = Decimal::from_str("INF").unwrap();
889 assert!(inf.is_pos_infinity());
890 }
891
892 #[test]
893 fn test_special_value_ordering() {
894 let neg_inf = Decimal::neg_infinity();
896 let neg_num = Decimal::from_str("-1000").unwrap();
897 let zero = Decimal::from_str("0").unwrap();
898 let pos_num = Decimal::from_str("1000").unwrap();
899 let pos_inf = Decimal::infinity();
900 let nan = Decimal::nan();
901
902 assert!(neg_inf < neg_num);
903 assert!(neg_num < zero);
904 assert!(zero < pos_num);
905 assert!(pos_num < pos_inf);
906 assert!(pos_inf < nan);
907
908 assert!(neg_inf.as_bytes() < neg_num.as_bytes());
910 assert!(neg_num.as_bytes() < zero.as_bytes());
911 assert!(zero.as_bytes() < pos_num.as_bytes());
912 assert!(pos_num.as_bytes() < pos_inf.as_bytes());
913 assert!(pos_inf.as_bytes() < nan.as_bytes());
914 }
915
916 #[test]
917 fn test_special_value_equality() {
918 let nan1 = Decimal::from_str("NaN").unwrap();
920 let nan2 = Decimal::from_str("nan").unwrap();
921 let nan3 = Decimal::nan();
922 assert_eq!(nan1, nan2);
923 assert_eq!(nan2, nan3);
924
925 let inf1 = Decimal::infinity();
927 let inf2 = Decimal::from_str("Infinity").unwrap();
928 assert_eq!(inf1, inf2);
929
930 let neg_inf1 = Decimal::neg_infinity();
931 let neg_inf2 = Decimal::from_str("-Infinity").unwrap();
932 assert_eq!(neg_inf1, neg_inf2);
933 }
934
935 #[test]
936 fn test_special_value_serialization() {
937 let inf = Decimal::infinity();
938 let json = serde_json::to_string(&inf).unwrap();
939 assert_eq!(json, "\"Infinity\"");
940 let restored: Decimal = serde_json::from_str(&json).unwrap();
941 assert_eq!(inf, restored);
942
943 let nan = Decimal::nan();
944 let json = serde_json::to_string(&nan).unwrap();
945 assert_eq!(json, "\"NaN\"");
946 let restored: Decimal = serde_json::from_str(&json).unwrap();
947 assert_eq!(nan, restored);
948 }
949
950 #[test]
951 fn test_special_value_byte_efficiency() {
952 assert_eq!(Decimal::infinity().byte_len(), 3);
954 assert_eq!(Decimal::neg_infinity().byte_len(), 3);
955 assert_eq!(Decimal::nan().byte_len(), 3);
956 }
957
958 #[test]
961 fn test_negative_scale() {
962 let d = Decimal::with_precision_scale("12345", Some(10), Some(-3)).unwrap();
964 assert_eq!(d.to_string(), "12000");
965
966 let d = Decimal::with_precision_scale("12500", Some(10), Some(-3)).unwrap();
968 assert_eq!(d.to_string(), "13000");
969
970 let d = Decimal::with_precision_scale("1234", Some(10), Some(-2)).unwrap();
972 assert_eq!(d.to_string(), "1200");
973 }
974
975 #[test]
976 fn test_negative_scale_with_precision() {
977 let d = Decimal::with_precision_scale("12345", Some(2), Some(-3)).unwrap();
979 assert_eq!(d.to_string(), "12000");
980 }
981
982 #[test]
985 fn test_invalid_format_errors() {
986 let result = Decimal::from_str("1.2.3");
988 assert!(result.is_err());
989 assert!(matches!(
990 result.unwrap_err(),
991 DecimalError::InvalidFormat(_)
992 ));
993
994 let result = Decimal::from_str("12abc");
996 assert!(result.is_err());
997
998 let result = Decimal::from_str("1e");
1000 assert!(result.is_err());
1001 assert!(matches!(
1002 result.unwrap_err(),
1003 DecimalError::InvalidFormat(_)
1004 ));
1005
1006 let result = Decimal::from_str("1eabc");
1008 assert!(result.is_err());
1009
1010 let d = Decimal::from_str("").unwrap();
1012 assert!(d.is_zero());
1013
1014 let result = Decimal::from_str("-");
1016 assert!(result.is_ok()); }
1018
1019 #[test]
1020 fn test_leading_plus_sign() {
1021 let d = Decimal::from_str("+123.456").unwrap();
1022 assert_eq!(d.to_string(), "123.456");
1023 assert!(d.is_positive());
1024 }
1025
1026 #[test]
1027 fn test_scientific_notation() {
1028 let d = Decimal::from_str("1.5e10").unwrap();
1029 assert_eq!(d.to_string(), "15000000000");
1030
1031 let d = Decimal::from_str("1.5E-3").unwrap();
1032 assert_eq!(d.to_string(), "0.0015");
1033
1034 let d = Decimal::from_str("1e+5").unwrap();
1035 assert_eq!(d.to_string(), "100000");
1036 }
1037
1038 #[test]
1039 fn test_leading_decimal_point() {
1040 let d = Decimal::from_str(".5").unwrap();
1042 assert_eq!(d.to_string(), "0.5");
1043
1044 let d = Decimal::from_str("-.25").unwrap();
1045 assert_eq!(d.to_string(), "-0.25");
1046 }
1047
1048 #[test]
1049 fn test_trailing_zeros() {
1050 let d = Decimal::from_str("100").unwrap();
1051 assert_eq!(d.to_string(), "100");
1052
1053 let d = Decimal::from_str("1.500").unwrap();
1054 assert_eq!(d.to_string(), "1.5");
1055 }
1056
1057 #[test]
1058 fn test_leading_zeros() {
1059 let d = Decimal::from_str("007").unwrap();
1060 assert_eq!(d.to_string(), "7");
1061
1062 let d = Decimal::from_str("00.123").unwrap();
1063 assert_eq!(d.to_string(), "0.123");
1064 }
1065
1066 #[test]
1069 fn test_into_bytes() {
1070 let d = Decimal::from_str("123.456").unwrap();
1071 let bytes_ref = d.as_bytes().to_vec();
1072 let bytes_owned = d.into_bytes();
1073 assert_eq!(bytes_ref, bytes_owned);
1074 }
1075
1076 #[test]
1077 fn test_clone() {
1078 let d1 = Decimal::from_str("123.456").unwrap();
1079 let d2 = d1.clone();
1080 assert_eq!(d1, d2);
1081 assert_eq!(d1.as_bytes(), d2.as_bytes());
1082 }
1083
1084 #[test]
1085 fn test_hash() {
1086 use std::collections::HashSet;
1087
1088 let mut set = HashSet::new();
1089 set.insert(Decimal::from_str("123.456").unwrap());
1090 set.insert(Decimal::from_str("123.456").unwrap()); set.insert(Decimal::from_str("789.012").unwrap());
1092
1093 assert_eq!(set.len(), 2);
1094 assert!(set.contains(&Decimal::from_str("123.456").unwrap()));
1095 }
1096
1097 #[test]
1098 fn test_debug_format() {
1099 let d = Decimal::from_str("123.456").unwrap();
1100 let debug_str = format!("{:?}", d);
1101 assert!(debug_str.contains("Decimal"));
1102 assert!(debug_str.contains("123.456"));
1103 }
1104
1105 #[test]
1106 fn test_ord_trait() {
1107 use std::cmp::Ordering;
1108
1109 let a = Decimal::from_str("1").unwrap();
1110 let b = Decimal::from_str("2").unwrap();
1111 let c = Decimal::from_str("1").unwrap();
1112
1113 assert_eq!(a.cmp(&b), Ordering::Less);
1114 assert_eq!(b.cmp(&a), Ordering::Greater);
1115 assert_eq!(a.cmp(&c), Ordering::Equal);
1116 }
1117
1118 #[test]
1119 fn test_from_bytes_invalid() {
1120 let result = Decimal::from_bytes(&[]);
1122 assert!(result.is_err());
1123
1124 let result = Decimal::from_bytes(&[0x00]);
1126 assert!(result.is_err());
1127 }
1128
1129 #[test]
1130 fn test_deserialize_from_string_number() {
1131 let d: Decimal = serde_json::from_str("\"42\"").unwrap();
1133 assert_eq!(d.to_string(), "42");
1134
1135 let d: Decimal = serde_json::from_str("\"-100\"").unwrap();
1136 assert_eq!(d.to_string(), "-100");
1137
1138 let d: Decimal = serde_json::from_str("\"1.5e10\"").unwrap();
1139 assert_eq!(d.to_string(), "15000000000");
1140 }
1141
1142 #[test]
1143 fn test_from_various_integer_types() {
1144 assert_eq!(Decimal::from(0i32).to_string(), "0");
1145 assert_eq!(Decimal::from(i32::MAX).to_string(), "2147483647");
1146 assert_eq!(Decimal::from(i32::MIN).to_string(), "-2147483648");
1147 assert_eq!(Decimal::from(i64::MAX).to_string(), "9223372036854775807");
1148 assert_eq!(Decimal::from(i64::MIN).to_string(), "-9223372036854775808");
1149 }
1150
1151 #[test]
1152 fn test_precision_overflow() {
1153 let result = Decimal::from_str("1e20000");
1155 assert!(result.is_err());
1156 assert!(matches!(
1157 result.unwrap_err(),
1158 DecimalError::PrecisionOverflow
1159 ));
1160
1161 let result = Decimal::from_str("1e-20000");
1163 assert!(result.is_err());
1164 assert!(matches!(
1165 result.unwrap_err(),
1166 DecimalError::PrecisionOverflow
1167 ));
1168 }
1169
1170 #[test]
1171 fn test_all_zeros_variations() {
1172 let d = Decimal::from_str("0").unwrap();
1173 assert!(d.is_zero());
1174
1175 let d = Decimal::from_str("0.0").unwrap();
1176 assert!(d.is_zero());
1177
1178 let d = Decimal::from_str("00.00").unwrap();
1179 assert!(d.is_zero());
1180
1181 let d = Decimal::from_str("-0").unwrap();
1182 assert!(d.is_zero());
1183 }
1185
1186 #[test]
1189 fn test_rounding_all_nines() {
1190 let d = Decimal::with_precision_scale("99.999", Some(10), Some(2)).unwrap();
1192 assert_eq!(d.to_string(), "100");
1193
1194 let d = Decimal::with_precision_scale("9.99", Some(10), Some(1)).unwrap();
1196 assert_eq!(d.to_string(), "10");
1197
1198 let d = Decimal::with_precision_scale("999", Some(10), Some(-1)).unwrap();
1200 assert_eq!(d.to_string(), "1000");
1201 }
1202
1203 #[test]
1204 fn test_negative_scale_small_number() {
1205 let d = Decimal::with_precision_scale("4", Some(10), Some(-1)).unwrap();
1207 assert_eq!(d.to_string(), "0");
1208
1209 let d = Decimal::with_precision_scale("5", Some(10), Some(-1)).unwrap();
1211 assert_eq!(d.to_string(), "10");
1212
1213 let d = Decimal::with_precision_scale("-4", Some(10), Some(-1)).unwrap();
1215 assert_eq!(d.to_string(), "0");
1216
1217 let d = Decimal::with_precision_scale("-5", Some(10), Some(-1)).unwrap();
1219 assert_eq!(d.to_string(), "-10");
1220 }
1221
1222 #[test]
1223 fn test_precision_truncation() {
1224 let d = Decimal::with_precision_scale("123456", Some(3), Some(0)).unwrap();
1226 assert_eq!(d.to_string(), "456");
1227
1228 let d = Decimal::with_precision_scale("12345.67", Some(4), Some(2)).unwrap();
1230 assert_eq!(d.to_string(), "45.67");
1231 }
1232
1233 #[test]
1234 fn test_very_small_numbers() {
1235 let d = Decimal::from_str("0.000000001").unwrap();
1236 assert_eq!(d.to_string(), "0.000000001");
1237 assert!(d.is_positive());
1238
1239 let d = Decimal::from_str("-0.000000001").unwrap();
1240 assert_eq!(d.to_string(), "-0.000000001");
1241 assert!(d.is_negative());
1242 }
1243
1244 #[test]
1245 fn test_very_large_numbers() {
1246 let d = Decimal::from_str("999999999999999999999999999999").unwrap();
1247 assert_eq!(d.to_string(), "999999999999999999999999999999");
1248
1249 let d = Decimal::from_str("-999999999999999999999999999999").unwrap();
1250 assert_eq!(d.to_string(), "-999999999999999999999999999999");
1251 }
1252
1253 #[test]
1254 fn test_max_exponent_boundary() {
1255 let d = Decimal::from_str("1e16000").unwrap();
1257 assert!(d.is_positive());
1258
1259 let result = Decimal::from_str("1e17000");
1261 assert!(result.is_err());
1262 }
1263
1264 #[test]
1265 fn test_min_exponent_boundary() {
1266 let d = Decimal::from_str("1e-16000").unwrap();
1268 assert!(d.is_positive());
1269
1270 let result = Decimal::from_str("1e-17000");
1272 assert!(result.is_err());
1273 }
1274
1275 #[test]
1276 fn test_odd_digit_count() {
1277 let d = Decimal::from_str("12345").unwrap();
1279 assert_eq!(d.to_string(), "12345");
1280
1281 let d = Decimal::from_str("1").unwrap();
1282 assert_eq!(d.to_string(), "1");
1283
1284 let d = Decimal::from_str("123").unwrap();
1285 assert_eq!(d.to_string(), "123");
1286 }
1287
1288 #[test]
1289 fn test_negative_number_ordering() {
1290 let a = Decimal::from_str("-100").unwrap();
1292 let b = Decimal::from_str("-10").unwrap();
1293 let c = Decimal::from_str("-1").unwrap();
1294
1295 assert!(a < b);
1297 assert!(b < c);
1298
1299 assert!(a.as_bytes() < b.as_bytes());
1301 assert!(b.as_bytes() < c.as_bytes());
1302 }
1303
1304 #[test]
1305 fn test_from_bytes_unchecked_roundtrip() {
1306 let original = Decimal::from_str("123.456").unwrap();
1307 let bytes = original.as_bytes().to_vec();
1308 let restored = Decimal::from_bytes_unchecked(bytes);
1309 assert_eq!(original, restored);
1310 }
1311
1312 #[test]
1313 fn test_special_value_checks() {
1314 let d = Decimal::from_str("123.456").unwrap();
1315 assert!(!d.is_nan());
1316 assert!(!d.is_infinity());
1317 assert!(!d.is_pos_infinity());
1318 assert!(!d.is_neg_infinity());
1319 assert!(!d.is_special());
1320 assert!(d.is_finite());
1321 }
1322
1323 #[test]
1324 fn test_equality_and_hash_consistency() {
1325 use std::collections::HashMap;
1326
1327 let d1 = Decimal::from_str("123.456").unwrap();
1328 let d2 = Decimal::from_str("123.456").unwrap();
1329 let d3 = Decimal::from_str("123.457").unwrap();
1330
1331 assert_eq!(d1, d2);
1333 assert_ne!(d1, d3);
1334
1335 let mut map = HashMap::new();
1337 map.insert(d1.clone(), "first");
1338 map.insert(d2.clone(), "second"); assert_eq!(map.len(), 1);
1340 assert_eq!(map.get(&d1), Some(&"second"));
1341 }
1342
1343 #[test]
1344 fn test_scale_zero() {
1345 let d = Decimal::with_precision_scale("123.999", Some(10), Some(0)).unwrap();
1347 assert_eq!(d.to_string(), "124"); }
1349
1350 #[test]
1351 fn test_only_fractional_with_precision_scale() {
1352 let d = Decimal::with_precision_scale(".5", Some(10), Some(2)).unwrap();
1353 assert_eq!(d.to_string(), "0.5");
1354 }
1355
1356 #[test]
1357 fn test_default_impl() {
1358 let d = Decimal::default();
1359 assert!(d.is_zero());
1360 assert_eq!(d.to_string(), "0");
1361 }
1362
1363 #[test]
1364 fn test_precision_zero_integer_digits() {
1365 let d = Decimal::with_precision_scale("123.456", Some(2), Some(2)).unwrap();
1368 assert_eq!(d.to_string(), "0.46");
1369 }
1370
1371 #[test]
1372 fn test_negative_with_precision_truncation() {
1373 let d = Decimal::with_precision_scale("-123.456", Some(3), Some(2)).unwrap();
1375 assert_eq!(d.to_string(), "-3.46");
1376 }
1377
1378 #[test]
1379 fn test_invalid_sign_byte() {
1380 let result = Decimal::from_bytes(&[0x01, 0x40, 0x00, 0x12]);
1385 assert!(result.is_err());
1386
1387 let result = Decimal::from_bytes(&[0x7F, 0x40, 0x00, 0x12]);
1389 assert!(result.is_err());
1390
1391 let result = Decimal::from_bytes(&[0xFE, 0x40, 0x00, 0x12]);
1393 assert!(result.is_err());
1394 }
1395
1396 #[test]
1397 fn test_invalid_bcd_encoding() {
1398 let invalid_bytes = vec![
1402 0xFF, 0x80, 0x00, 0xAB, ];
1406 let result = Decimal::from_bytes(&invalid_bytes);
1407 assert!(result.is_err());
1408
1409 let invalid_bytes = vec![
1411 0xFF, 0x80, 0x00, 0xA1, ];
1415 let result = Decimal::from_bytes(&invalid_bytes);
1416 assert!(result.is_err());
1417
1418 let invalid_bytes = vec![
1420 0xFF, 0x80, 0x00, 0x1B, ];
1424 let result = Decimal::from_bytes(&invalid_bytes);
1425 assert!(result.is_err());
1426 }
1427
1428 #[test]
1429 fn test_reserved_exponent_positive() {
1430 let bytes_with_reserved_exp = vec![
1437 0xFF, 0xFF, 0xFF, 0x12, ];
1441 let result = Decimal::from_bytes(&bytes_with_reserved_exp);
1442 assert!(result.is_err());
1443
1444 let bytes_with_reserved_exp = vec![
1446 0xFF, 0xFF, 0xFE, 0x12, ];
1450 let result = Decimal::from_bytes(&bytes_with_reserved_exp);
1451 assert!(result.is_err());
1452 }
1453
1454 #[test]
1455 fn test_reserved_exponent_negative() {
1456 let bytes_with_reserved_exp = vec![
1461 0x00, 0x00, 0x00, 0x12, ];
1465 let result = Decimal::from_bytes(&bytes_with_reserved_exp);
1466 assert!(result.is_err());
1467 }
1468
1469 #[test]
1470 fn test_empty_mantissa_bytes() {
1471 let bytes_no_mantissa = vec![
1474 0xFF, 0x80, 0x00, ];
1478 let d = Decimal::from_bytes(&bytes_no_mantissa).unwrap();
1479 assert_eq!(d.to_string(), "0");
1480 }
1481
1482 #[cfg(feature = "rust_decimal")]
1485 mod rust_decimal_tests {
1486 use super::*;
1487
1488 #[test]
1489 fn test_from_rust_decimal() {
1490 use rust_decimal::Decimal as RustDecimal;
1491
1492 let rd = RustDecimal::new(12345, 2); let d: Decimal = rd.try_into().unwrap();
1494 assert_eq!(d.to_string(), "123.45");
1495 }
1496
1497 #[test]
1498 fn test_to_rust_decimal() {
1499 use rust_decimal::Decimal as RustDecimal;
1500
1501 let d = Decimal::from_str("123.45").unwrap();
1502 let rd: RustDecimal = (&d).try_into().unwrap();
1503 assert_eq!(rd.to_string(), "123.45");
1504 }
1505
1506 #[test]
1507 fn test_rust_decimal_roundtrip() {
1508 use rust_decimal::Decimal as RustDecimal;
1509
1510 let values = vec!["0", "1", "-1", "123.456", "-999.999", "0.001"];
1511
1512 for s in values {
1513 let d = Decimal::from_str(s).unwrap();
1514 let rd: RustDecimal = (&d).try_into().unwrap();
1515 let d2: Decimal = rd.try_into().unwrap();
1516 assert_eq!(d, d2, "Roundtrip failed for {}", s);
1517 }
1518 }
1519
1520 #[test]
1521 fn test_rust_decimal_arithmetic() {
1522 use rust_decimal::Decimal as RustDecimal;
1523
1524 let a = Decimal::from_str("100.50").unwrap();
1526 let b = Decimal::from_str("25.25").unwrap();
1527
1528 let ra: RustDecimal = (&a).try_into().unwrap();
1530 let rb: RustDecimal = (&b).try_into().unwrap();
1531 let sum = ra + rb;
1532
1533 let result: Decimal = sum.try_into().unwrap();
1535 assert_eq!(result.to_string(), "125.75");
1536 }
1537
1538 #[test]
1539 fn test_rust_decimal_from_owned() {
1540 use rust_decimal::Decimal as RustDecimal;
1541
1542 let d = Decimal::from_str("456.789").unwrap();
1544 let rd: RustDecimal = d.try_into().unwrap();
1545 assert_eq!(rd.to_string(), "456.789");
1546 }
1547
1548 #[test]
1549 fn test_rust_decimal_special_values_fail() {
1550 use rust_decimal::Decimal as RustDecimal;
1551
1552 let inf = Decimal::infinity();
1554 let result: Result<RustDecimal, _> = (&inf).try_into();
1555 assert!(result.is_err());
1556
1557 let nan = Decimal::nan();
1559 let result: Result<RustDecimal, _> = (&nan).try_into();
1560 assert!(result.is_err());
1561 }
1562 }
1563
1564 #[cfg(feature = "bigdecimal")]
1567 mod bigdecimal_tests {
1568 use super::*;
1569
1570 #[test]
1571 fn test_from_bigdecimal() {
1572 use bigdecimal::BigDecimal;
1573 use std::str::FromStr;
1574
1575 let bd = BigDecimal::from_str("123.45").unwrap();
1576 let d: Decimal = bd.try_into().unwrap();
1577 assert_eq!(d.to_string(), "123.45");
1578 }
1579
1580 #[test]
1581 fn test_to_bigdecimal() {
1582 use bigdecimal::BigDecimal;
1583
1584 let d = Decimal::from_str("123.45").unwrap();
1585 let bd: BigDecimal = (&d).try_into().unwrap();
1586 assert_eq!(bd.to_string(), "123.45");
1587 }
1588
1589 #[test]
1590 fn test_bigdecimal_roundtrip() {
1591 use bigdecimal::BigDecimal;
1592
1593 let values = vec!["0", "1", "-1", "123.456", "-999.999", "0.001"];
1594
1595 for s in values {
1596 let d = Decimal::from_str(s).unwrap();
1597 let bd: BigDecimal = (&d).try_into().unwrap();
1598 let d2: Decimal = bd.try_into().unwrap();
1599 assert_eq!(d, d2, "Roundtrip failed for {}", s);
1600 }
1601 }
1602
1603 #[test]
1604 fn test_bigdecimal_from_owned() {
1605 use bigdecimal::BigDecimal;
1606
1607 let d = Decimal::from_str("456.789").unwrap();
1609 let bd: BigDecimal = d.try_into().unwrap();
1610 assert_eq!(bd.to_string(), "456.789");
1611 }
1612
1613 #[test]
1614 fn test_bigdecimal_from_ref() {
1615 use bigdecimal::BigDecimal;
1616 use std::str::FromStr;
1617
1618 let bd = BigDecimal::from_str("789.012").unwrap();
1620 let d: Decimal = (&bd).try_into().unwrap();
1621 assert_eq!(d.to_string(), "789.012");
1622 }
1623
1624 #[test]
1625 fn test_bigdecimal_special_values_fail() {
1626 use bigdecimal::BigDecimal;
1627
1628 let inf = Decimal::infinity();
1630 let result: Result<BigDecimal, _> = (&inf).try_into();
1631 assert!(result.is_err());
1632
1633 let nan = Decimal::nan();
1635 let result: Result<BigDecimal, _> = (&nan).try_into();
1636 assert!(result.is_err());
1637 }
1638 }
1639}