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 {
417 decode_to_string_with_scale(&self.bytes, scale).expect("Decimal contains valid bytes")
418 }
419}
420
421impl FromStr for Decimal {
422 type Err = DecimalError;
423
424 fn from_str(s: &str) -> Result<Self, Self::Err> {
439 let bytes = encode_decimal(s)?;
440 Ok(Self { bytes })
441 }
442}
443
444impl fmt::Display for Decimal {
445 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
446 let s = decode_to_string(&self.bytes).expect("Decimal contains valid bytes");
447 write!(f, "{}", s)
448 }
449}
450
451impl fmt::Debug for Decimal {
452 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
453 let value = decode_to_string(&self.bytes).expect("Decimal contains valid bytes");
454 f.debug_struct("Decimal")
455 .field("value", &value)
456 .field("bytes", &self.bytes)
457 .finish()
458 }
459}
460
461impl PartialEq for Decimal {
462 fn eq(&self, other: &Self) -> bool {
463 self.bytes == other.bytes
464 }
465}
466
467impl Eq for Decimal {}
468
469impl PartialOrd for Decimal {
470 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
471 Some(self.cmp(other))
472 }
473}
474
475impl Ord for Decimal {
476 fn cmp(&self, other: &Self) -> Ordering {
477 self.bytes.cmp(&other.bytes)
479 }
480}
481
482impl Hash for Decimal {
483 fn hash<H: Hasher>(&self, state: &mut H) {
484 self.bytes.hash(state);
485 }
486}
487
488impl Serialize for Decimal {
489 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
490 where
491 S: Serializer,
492 {
493 serializer.serialize_str(&self.to_string())
495 }
496}
497
498impl<'de> Deserialize<'de> for Decimal {
499 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
500 where
501 D: Deserializer<'de>,
502 {
503 let s = String::deserialize(deserializer)?;
504 Decimal::from_str(&s).map_err(serde::de::Error::custom)
505 }
506}
507
508macro_rules! impl_from_int {
510 ($($t:ty),*) => {
511 $(
512 impl From<$t> for Decimal {
513 fn from(val: $t) -> Self {
514 Decimal::from_str(&val.to_string()).expect("Integer is always valid")
518 }
519 }
520 )*
521 };
522}
523
524impl_from_int!(i8, i16, i32, i64, i128, u8, u16, u32, u64, u128);
525
526impl TryFrom<f64> for Decimal {
527 type Error = DecimalError;
528
529 fn try_from(val: f64) -> Result<Self, Self::Error> {
555 if val.is_nan() {
556 return Ok(Decimal::nan());
557 }
558 if val.is_infinite() {
559 return Ok(if val.is_sign_positive() {
560 Decimal::infinity()
561 } else {
562 Decimal::neg_infinity()
563 });
564 }
565 Decimal::from_str(&val.to_string())
566 }
567}
568
569impl Default for Decimal {
570 fn default() -> Self {
571 Decimal {
572 bytes: vec![encoding::SIGN_ZERO],
573 }
574 }
575}
576
577#[cfg(feature = "rust_decimal")]
582mod rust_decimal_interop {
583 use super::{Decimal, DecimalError};
584 use std::str::FromStr;
585
586 impl TryFrom<rust_decimal::Decimal> for Decimal {
587 type Error = DecimalError;
588
589 fn try_from(value: rust_decimal::Decimal) -> Result<Self, Self::Error> {
602 Decimal::from_str(&value.to_string())
603 }
604 }
605
606 impl TryFrom<&Decimal> for rust_decimal::Decimal {
607 type Error = rust_decimal::Error;
608
609 fn try_from(value: &Decimal) -> Result<Self, Self::Error> {
625 use std::str::FromStr;
626 rust_decimal::Decimal::from_str(&value.to_string())
627 }
628 }
629
630 impl TryFrom<Decimal> for rust_decimal::Decimal {
631 type Error = rust_decimal::Error;
632
633 fn try_from(value: Decimal) -> Result<Self, Self::Error> {
634 rust_decimal::Decimal::try_from(&value)
635 }
636 }
637}
638
639#[cfg(feature = "bigdecimal")]
647mod bigdecimal_interop {
648 use super::{Decimal, DecimalError};
649 use std::str::FromStr;
650
651 impl TryFrom<bigdecimal::BigDecimal> for Decimal {
652 type Error = DecimalError;
653
654 fn try_from(value: bigdecimal::BigDecimal) -> Result<Self, Self::Error> {
656 Decimal::from_str(&value.to_string())
657 }
658 }
659
660 impl TryFrom<&bigdecimal::BigDecimal> for Decimal {
661 type Error = DecimalError;
662
663 fn try_from(value: &bigdecimal::BigDecimal) -> Result<Self, Self::Error> {
664 Decimal::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> {
676 use std::str::FromStr;
677 bigdecimal::BigDecimal::from_str(&value.to_string())
678 }
679 }
680
681 impl TryFrom<Decimal> for bigdecimal::BigDecimal {
682 type Error = bigdecimal::ParseBigDecimalError;
683
684 fn try_from(value: Decimal) -> Result<Self, Self::Error> {
685 bigdecimal::BigDecimal::try_from(&value)
686 }
687 }
688}
689
690#[cfg(test)]
694mod tests {
695 use super::*;
696
697 #[test]
698 fn test_from_str() {
699 let d = Decimal::from_str("123.456").unwrap();
700 assert_eq!(d.to_string(), "123.456");
701 }
702
703 #[test]
704 fn test_zero() {
705 let d = Decimal::from_str("0").unwrap();
706 assert!(d.is_zero());
707 assert!(!d.is_negative());
708 assert!(!d.is_positive());
709 assert!(d.is_finite());
710 assert!(!d.is_special());
711 }
712
713 #[test]
714 fn test_negative() {
715 let d = Decimal::from_str("-123.456").unwrap();
716 assert!(d.is_negative());
717 assert!(!d.is_zero());
718 assert!(!d.is_positive());
719 assert!(d.is_finite());
720 }
721
722 #[test]
723 fn test_positive() {
724 let d = Decimal::from_str("123.456").unwrap();
725 assert!(d.is_positive());
726 assert!(!d.is_zero());
727 assert!(!d.is_negative());
728 assert!(d.is_finite());
729 }
730
731 #[test]
732 fn test_ordering() {
733 let values = vec!["-100", "-10", "-1", "-0.1", "0", "0.1", "1", "10", "100"];
734 let decimals: Vec<Decimal> = values
735 .iter()
736 .map(|s| Decimal::from_str(s).unwrap())
737 .collect();
738
739 for i in 0..decimals.len() - 1 {
741 assert!(
742 decimals[i] < decimals[i + 1],
743 "{} should be < {}",
744 values[i],
745 values[i + 1]
746 );
747 }
748
749 for i in 0..decimals.len() - 1 {
751 assert!(
752 decimals[i].as_bytes() < decimals[i + 1].as_bytes(),
753 "bytes of {} should be < bytes of {}",
754 values[i],
755 values[i + 1]
756 );
757 }
758 }
759
760 #[test]
761 fn test_roundtrip() {
762 let values = vec![
763 "0", "1", "-1", "123.456", "-123.456", "0.001", "0.1", "10", "100", "1000000",
764 "-1000000",
765 ];
766
767 for s in values {
768 let d = Decimal::from_str(s).unwrap();
769 let bytes = d.as_bytes();
770 let restored = Decimal::from_bytes(bytes).unwrap();
771 assert_eq!(d, restored, "Roundtrip failed for {}", s);
772 }
773 }
774
775 #[test]
776 fn test_precision_scale() {
777 let d = Decimal::with_precision_scale("123.456", Some(10), Some(2)).unwrap();
779 assert_eq!(d.to_string(), "123.46");
780
781 let d = Decimal::with_precision_scale("12345.67", Some(5), Some(2)).unwrap();
783 assert_eq!(d.to_string(), "345.67"); let d = Decimal::with_precision_scale("99.999", Some(5), Some(2)).unwrap();
787 assert_eq!(d.to_string(), "100"); }
789
790 #[test]
791 fn test_from_integer() {
792 let d = Decimal::from(42i64);
793 assert_eq!(d.to_string(), "42");
794
795 let d = Decimal::from(-100i32);
796 assert_eq!(d.to_string(), "-100");
797 }
798
799 #[test]
800 fn test_from_f64() {
801 let d: Decimal = 123.456f64.try_into().unwrap();
803 assert_eq!(d.to_string(), "123.456");
804
805 let d: Decimal = (-99.5f64).try_into().unwrap();
806 assert_eq!(d.to_string(), "-99.5");
807
808 let d: Decimal = 0.0f64.try_into().unwrap();
809 assert!(d.is_zero());
810
811 let inf: Decimal = f64::INFINITY.try_into().unwrap();
813 assert!(inf.is_pos_infinity());
814
815 let neg_inf: Decimal = f64::NEG_INFINITY.try_into().unwrap();
816 assert!(neg_inf.is_neg_infinity());
817
818 let nan: Decimal = f64::NAN.try_into().unwrap();
819 assert!(nan.is_nan());
820 }
821
822 #[test]
823 fn test_serialization() {
824 let d = Decimal::from_str("123.456").unwrap();
825 let json = serde_json::to_string(&d).unwrap();
826 assert_eq!(json, "\"123.456\"");
827
828 let restored: Decimal = serde_json::from_str(&json).unwrap();
829 assert_eq!(d, restored);
830 }
831
832 #[test]
833 fn test_byte_efficiency() {
834 let d = Decimal::from_str("123456789").unwrap();
836 assert!(
838 d.byte_len() <= 10,
839 "Expected <= 10 bytes, got {}",
840 d.byte_len()
841 );
842
843 let d = Decimal::from_str("0.000001").unwrap();
844 assert!(
846 d.byte_len() <= 6,
847 "Expected <= 6 bytes, got {}",
848 d.byte_len()
849 );
850 }
851
852 #[test]
855 fn test_infinity_creation() {
856 let pos_inf = Decimal::infinity();
857 assert!(pos_inf.is_pos_infinity());
858 assert!(pos_inf.is_infinity());
859 assert!(!pos_inf.is_neg_infinity());
860 assert!(!pos_inf.is_nan());
861 assert!(pos_inf.is_special());
862 assert!(!pos_inf.is_finite());
863 assert_eq!(pos_inf.to_string(), "Infinity");
864
865 let neg_inf = Decimal::neg_infinity();
866 assert!(neg_inf.is_neg_infinity());
867 assert!(neg_inf.is_infinity());
868 assert!(!neg_inf.is_pos_infinity());
869 assert!(!neg_inf.is_nan());
870 assert!(neg_inf.is_special());
871 assert!(!neg_inf.is_finite());
872 assert_eq!(neg_inf.to_string(), "-Infinity");
873 }
874
875 #[test]
876 fn test_nan_creation() {
877 let nan = Decimal::nan();
878 assert!(nan.is_nan());
879 assert!(nan.is_special());
880 assert!(!nan.is_finite());
881 assert!(!nan.is_infinity());
882 assert!(!nan.is_zero());
883 assert_eq!(nan.to_string(), "NaN");
884 }
885
886 #[test]
887 fn test_special_value_from_str() {
888 let pos_inf = Decimal::from_str("Infinity").unwrap();
889 assert!(pos_inf.is_pos_infinity());
890
891 let neg_inf = Decimal::from_str("-Infinity").unwrap();
892 assert!(neg_inf.is_neg_infinity());
893
894 let nan = Decimal::from_str("NaN").unwrap();
895 assert!(nan.is_nan());
896
897 let inf = Decimal::from_str("infinity").unwrap();
899 assert!(inf.is_pos_infinity());
900
901 let inf = Decimal::from_str("INF").unwrap();
902 assert!(inf.is_pos_infinity());
903 }
904
905 #[test]
906 fn test_special_value_ordering() {
907 let neg_inf = Decimal::neg_infinity();
909 let neg_num = Decimal::from_str("-1000").unwrap();
910 let zero = Decimal::from_str("0").unwrap();
911 let pos_num = Decimal::from_str("1000").unwrap();
912 let pos_inf = Decimal::infinity();
913 let nan = Decimal::nan();
914
915 assert!(neg_inf < neg_num);
916 assert!(neg_num < zero);
917 assert!(zero < pos_num);
918 assert!(pos_num < pos_inf);
919 assert!(pos_inf < nan);
920
921 assert!(neg_inf.as_bytes() < neg_num.as_bytes());
923 assert!(neg_num.as_bytes() < zero.as_bytes());
924 assert!(zero.as_bytes() < pos_num.as_bytes());
925 assert!(pos_num.as_bytes() < pos_inf.as_bytes());
926 assert!(pos_inf.as_bytes() < nan.as_bytes());
927 }
928
929 #[test]
930 fn test_special_value_equality() {
931 let nan1 = Decimal::from_str("NaN").unwrap();
933 let nan2 = Decimal::from_str("nan").unwrap();
934 let nan3 = Decimal::nan();
935 assert_eq!(nan1, nan2);
936 assert_eq!(nan2, nan3);
937
938 let inf1 = Decimal::infinity();
940 let inf2 = Decimal::from_str("Infinity").unwrap();
941 assert_eq!(inf1, inf2);
942
943 let neg_inf1 = Decimal::neg_infinity();
944 let neg_inf2 = Decimal::from_str("-Infinity").unwrap();
945 assert_eq!(neg_inf1, neg_inf2);
946 }
947
948 #[test]
949 fn test_special_value_serialization() {
950 let inf = Decimal::infinity();
951 let json = serde_json::to_string(&inf).unwrap();
952 assert_eq!(json, "\"Infinity\"");
953 let restored: Decimal = serde_json::from_str(&json).unwrap();
954 assert_eq!(inf, restored);
955
956 let nan = Decimal::nan();
957 let json = serde_json::to_string(&nan).unwrap();
958 assert_eq!(json, "\"NaN\"");
959 let restored: Decimal = serde_json::from_str(&json).unwrap();
960 assert_eq!(nan, restored);
961 }
962
963 #[test]
964 fn test_special_value_byte_efficiency() {
965 assert_eq!(Decimal::infinity().byte_len(), 3);
967 assert_eq!(Decimal::neg_infinity().byte_len(), 3);
968 assert_eq!(Decimal::nan().byte_len(), 3);
969 }
970
971 #[test]
974 fn test_negative_scale() {
975 let d = Decimal::with_precision_scale("12345", Some(10), Some(-3)).unwrap();
977 assert_eq!(d.to_string(), "12000");
978
979 let d = Decimal::with_precision_scale("12500", Some(10), Some(-3)).unwrap();
981 assert_eq!(d.to_string(), "13000");
982
983 let d = Decimal::with_precision_scale("1234", Some(10), Some(-2)).unwrap();
985 assert_eq!(d.to_string(), "1200");
986 }
987
988 #[test]
989 fn test_negative_scale_with_precision() {
990 let d = Decimal::with_precision_scale("12345", Some(2), Some(-3)).unwrap();
992 assert_eq!(d.to_string(), "12000");
993 }
994
995 #[test]
998 fn test_invalid_format_errors() {
999 let result = Decimal::from_str("1.2.3");
1001 assert!(result.is_err());
1002 assert!(matches!(
1003 result.unwrap_err(),
1004 DecimalError::InvalidFormat(_)
1005 ));
1006
1007 let result = Decimal::from_str("12abc");
1009 assert!(result.is_err());
1010
1011 let result = Decimal::from_str("1e");
1013 assert!(result.is_err());
1014 assert!(matches!(
1015 result.unwrap_err(),
1016 DecimalError::InvalidFormat(_)
1017 ));
1018
1019 let result = Decimal::from_str("1eabc");
1021 assert!(result.is_err());
1022
1023 let d = Decimal::from_str("").unwrap();
1025 assert!(d.is_zero());
1026
1027 let result = Decimal::from_str("-");
1029 assert!(result.is_ok()); }
1031
1032 #[test]
1033 fn test_leading_plus_sign() {
1034 let d = Decimal::from_str("+123.456").unwrap();
1035 assert_eq!(d.to_string(), "123.456");
1036 assert!(d.is_positive());
1037 }
1038
1039 #[test]
1040 fn test_scientific_notation() {
1041 let d = Decimal::from_str("1.5e10").unwrap();
1042 assert_eq!(d.to_string(), "15000000000");
1043
1044 let d = Decimal::from_str("1.5E-3").unwrap();
1045 assert_eq!(d.to_string(), "0.0015");
1046
1047 let d = Decimal::from_str("1e+5").unwrap();
1048 assert_eq!(d.to_string(), "100000");
1049 }
1050
1051 #[test]
1052 fn test_leading_decimal_point() {
1053 let d = Decimal::from_str(".5").unwrap();
1055 assert_eq!(d.to_string(), "0.5");
1056
1057 let d = Decimal::from_str("-.25").unwrap();
1058 assert_eq!(d.to_string(), "-0.25");
1059 }
1060
1061 #[test]
1062 fn test_trailing_zeros() {
1063 let d = Decimal::from_str("100").unwrap();
1064 assert_eq!(d.to_string(), "100");
1065
1066 let d = Decimal::from_str("1.500").unwrap();
1067 assert_eq!(d.to_string(), "1.5");
1068 }
1069
1070 #[test]
1071 fn test_leading_zeros() {
1072 let d = Decimal::from_str("007").unwrap();
1073 assert_eq!(d.to_string(), "7");
1074
1075 let d = Decimal::from_str("00.123").unwrap();
1076 assert_eq!(d.to_string(), "0.123");
1077 }
1078
1079 #[test]
1082 fn test_into_bytes() {
1083 let d = Decimal::from_str("123.456").unwrap();
1084 let bytes_ref = d.as_bytes().to_vec();
1085 let bytes_owned = d.into_bytes();
1086 assert_eq!(bytes_ref, bytes_owned);
1087 }
1088
1089 #[test]
1090 fn test_clone() {
1091 let d1 = Decimal::from_str("123.456").unwrap();
1092 let d2 = d1.clone();
1093 assert_eq!(d1, d2);
1094 assert_eq!(d1.as_bytes(), d2.as_bytes());
1095 }
1096
1097 #[test]
1098 fn test_hash() {
1099 use std::collections::HashSet;
1100
1101 let mut set = HashSet::new();
1102 set.insert(Decimal::from_str("123.456").unwrap());
1103 set.insert(Decimal::from_str("123.456").unwrap()); set.insert(Decimal::from_str("789.012").unwrap());
1105
1106 assert_eq!(set.len(), 2);
1107 assert!(set.contains(&Decimal::from_str("123.456").unwrap()));
1108 }
1109
1110 #[test]
1111 fn test_debug_format() {
1112 let d = Decimal::from_str("123.456").unwrap();
1113 let debug_str = format!("{:?}", d);
1114 assert!(debug_str.contains("Decimal"));
1115 assert!(debug_str.contains("123.456"));
1116 }
1117
1118 #[test]
1119 fn test_ord_trait() {
1120 use std::cmp::Ordering;
1121
1122 let a = Decimal::from_str("1").unwrap();
1123 let b = Decimal::from_str("2").unwrap();
1124 let c = Decimal::from_str("1").unwrap();
1125
1126 assert_eq!(a.cmp(&b), Ordering::Less);
1127 assert_eq!(b.cmp(&a), Ordering::Greater);
1128 assert_eq!(a.cmp(&c), Ordering::Equal);
1129 }
1130
1131 #[test]
1132 fn test_from_bytes_invalid() {
1133 let result = Decimal::from_bytes(&[]);
1135 assert!(result.is_err());
1136
1137 let result = Decimal::from_bytes(&[0x00]);
1139 assert!(result.is_err());
1140 }
1141
1142 #[test]
1143 fn test_deserialize_from_string_number() {
1144 let d: Decimal = serde_json::from_str("\"42\"").unwrap();
1146 assert_eq!(d.to_string(), "42");
1147
1148 let d: Decimal = serde_json::from_str("\"-100\"").unwrap();
1149 assert_eq!(d.to_string(), "-100");
1150
1151 let d: Decimal = serde_json::from_str("\"1.5e10\"").unwrap();
1152 assert_eq!(d.to_string(), "15000000000");
1153 }
1154
1155 #[test]
1156 fn test_from_various_integer_types() {
1157 assert_eq!(Decimal::from(0i32).to_string(), "0");
1158 assert_eq!(Decimal::from(i32::MAX).to_string(), "2147483647");
1159 assert_eq!(Decimal::from(i32::MIN).to_string(), "-2147483648");
1160 assert_eq!(Decimal::from(i64::MAX).to_string(), "9223372036854775807");
1161 assert_eq!(Decimal::from(i64::MIN).to_string(), "-9223372036854775808");
1162 }
1163
1164 #[test]
1165 fn test_precision_overflow() {
1166 let result = Decimal::from_str("1e20000");
1168 assert!(result.is_err());
1169 assert!(matches!(
1170 result.unwrap_err(),
1171 DecimalError::PrecisionOverflow
1172 ));
1173
1174 let result = Decimal::from_str("1e-20000");
1176 assert!(result.is_err());
1177 assert!(matches!(
1178 result.unwrap_err(),
1179 DecimalError::PrecisionOverflow
1180 ));
1181 }
1182
1183 #[test]
1184 fn test_all_zeros_variations() {
1185 let d = Decimal::from_str("0").unwrap();
1186 assert!(d.is_zero());
1187
1188 let d = Decimal::from_str("0.0").unwrap();
1189 assert!(d.is_zero());
1190
1191 let d = Decimal::from_str("00.00").unwrap();
1192 assert!(d.is_zero());
1193
1194 let d = Decimal::from_str("-0").unwrap();
1195 assert!(d.is_zero());
1196 }
1198
1199 #[test]
1202 fn test_rounding_all_nines() {
1203 let d = Decimal::with_precision_scale("99.999", Some(10), Some(2)).unwrap();
1205 assert_eq!(d.to_string(), "100");
1206
1207 let d = Decimal::with_precision_scale("9.99", Some(10), Some(1)).unwrap();
1209 assert_eq!(d.to_string(), "10");
1210
1211 let d = Decimal::with_precision_scale("999", Some(10), Some(-1)).unwrap();
1213 assert_eq!(d.to_string(), "1000");
1214 }
1215
1216 #[test]
1217 fn test_negative_scale_small_number() {
1218 let d = Decimal::with_precision_scale("4", Some(10), Some(-1)).unwrap();
1220 assert_eq!(d.to_string(), "0");
1221
1222 let d = Decimal::with_precision_scale("5", Some(10), Some(-1)).unwrap();
1224 assert_eq!(d.to_string(), "10");
1225
1226 let d = Decimal::with_precision_scale("-4", Some(10), Some(-1)).unwrap();
1228 assert_eq!(d.to_string(), "0");
1229
1230 let d = Decimal::with_precision_scale("-5", Some(10), Some(-1)).unwrap();
1232 assert_eq!(d.to_string(), "-10");
1233 }
1234
1235 #[test]
1236 fn test_precision_truncation() {
1237 let d = Decimal::with_precision_scale("123456", Some(3), Some(0)).unwrap();
1239 assert_eq!(d.to_string(), "456");
1240
1241 let d = Decimal::with_precision_scale("12345.67", Some(4), Some(2)).unwrap();
1243 assert_eq!(d.to_string(), "45.67");
1244 }
1245
1246 #[test]
1247 fn test_very_small_numbers() {
1248 let d = Decimal::from_str("0.000000001").unwrap();
1249 assert_eq!(d.to_string(), "0.000000001");
1250 assert!(d.is_positive());
1251
1252 let d = Decimal::from_str("-0.000000001").unwrap();
1253 assert_eq!(d.to_string(), "-0.000000001");
1254 assert!(d.is_negative());
1255 }
1256
1257 #[test]
1258 fn test_very_large_numbers() {
1259 let d = Decimal::from_str("999999999999999999999999999999").unwrap();
1260 assert_eq!(d.to_string(), "999999999999999999999999999999");
1261
1262 let d = Decimal::from_str("-999999999999999999999999999999").unwrap();
1263 assert_eq!(d.to_string(), "-999999999999999999999999999999");
1264 }
1265
1266 #[test]
1267 fn test_max_exponent_boundary() {
1268 let d = Decimal::from_str("1e16000").unwrap();
1270 assert!(d.is_positive());
1271
1272 let result = Decimal::from_str("1e17000");
1274 assert!(result.is_err());
1275 }
1276
1277 #[test]
1278 fn test_min_exponent_boundary() {
1279 let d = Decimal::from_str("1e-16000").unwrap();
1281 assert!(d.is_positive());
1282
1283 let result = Decimal::from_str("1e-17000");
1285 assert!(result.is_err());
1286 }
1287
1288 #[test]
1289 fn test_odd_digit_count() {
1290 let d = Decimal::from_str("12345").unwrap();
1292 assert_eq!(d.to_string(), "12345");
1293
1294 let d = Decimal::from_str("1").unwrap();
1295 assert_eq!(d.to_string(), "1");
1296
1297 let d = Decimal::from_str("123").unwrap();
1298 assert_eq!(d.to_string(), "123");
1299 }
1300
1301 #[test]
1302 fn test_negative_number_ordering() {
1303 let a = Decimal::from_str("-100").unwrap();
1305 let b = Decimal::from_str("-10").unwrap();
1306 let c = Decimal::from_str("-1").unwrap();
1307
1308 assert!(a < b);
1310 assert!(b < c);
1311
1312 assert!(a.as_bytes() < b.as_bytes());
1314 assert!(b.as_bytes() < c.as_bytes());
1315 }
1316
1317 #[test]
1318 fn test_from_bytes_unchecked_roundtrip() {
1319 let original = Decimal::from_str("123.456").unwrap();
1320 let bytes = original.as_bytes().to_vec();
1321 let restored = Decimal::from_bytes_unchecked(bytes);
1322 assert_eq!(original, restored);
1323 }
1324
1325 #[test]
1326 fn test_special_value_checks() {
1327 let d = Decimal::from_str("123.456").unwrap();
1328 assert!(!d.is_nan());
1329 assert!(!d.is_infinity());
1330 assert!(!d.is_pos_infinity());
1331 assert!(!d.is_neg_infinity());
1332 assert!(!d.is_special());
1333 assert!(d.is_finite());
1334 }
1335
1336 #[test]
1337 fn test_equality_and_hash_consistency() {
1338 use std::collections::HashMap;
1339
1340 let d1 = Decimal::from_str("123.456").unwrap();
1341 let d2 = Decimal::from_str("123.456").unwrap();
1342 let d3 = Decimal::from_str("123.457").unwrap();
1343
1344 assert_eq!(d1, d2);
1346 assert_ne!(d1, d3);
1347
1348 let mut map = HashMap::new();
1350 map.insert(d1.clone(), "first");
1351 map.insert(d2.clone(), "second"); assert_eq!(map.len(), 1);
1353 assert_eq!(map.get(&d1), Some(&"second"));
1354 }
1355
1356 #[test]
1357 fn test_scale_zero() {
1358 let d = Decimal::with_precision_scale("123.999", Some(10), Some(0)).unwrap();
1360 assert_eq!(d.to_string(), "124"); }
1362
1363 #[test]
1364 fn test_only_fractional_with_precision_scale() {
1365 let d = Decimal::with_precision_scale(".5", Some(10), Some(2)).unwrap();
1366 assert_eq!(d.to_string(), "0.5");
1367 }
1368
1369 #[test]
1370 fn test_default_impl() {
1371 let d = Decimal::default();
1372 assert!(d.is_zero());
1373 assert_eq!(d.to_string(), "0");
1374 }
1375
1376 #[test]
1377 fn test_precision_zero_integer_digits() {
1378 let d = Decimal::with_precision_scale("123.456", Some(2), Some(2)).unwrap();
1381 assert_eq!(d.to_string(), "0.46");
1382 }
1383
1384 #[test]
1385 fn test_negative_with_precision_truncation() {
1386 let d = Decimal::with_precision_scale("-123.456", Some(3), Some(2)).unwrap();
1388 assert_eq!(d.to_string(), "-3.46");
1389 }
1390
1391 #[test]
1392 fn test_invalid_sign_byte() {
1393 let result = Decimal::from_bytes(&[0x01, 0x40, 0x00, 0x12]);
1398 assert!(result.is_err());
1399
1400 let result = Decimal::from_bytes(&[0x7F, 0x40, 0x00, 0x12]);
1402 assert!(result.is_err());
1403
1404 let result = Decimal::from_bytes(&[0xFE, 0x40, 0x00, 0x12]);
1406 assert!(result.is_err());
1407 }
1408
1409 #[test]
1410 fn test_invalid_bcd_encoding() {
1411 let invalid_bytes = vec![
1415 0xFF, 0x80, 0x00, 0xAB, ];
1419 let result = Decimal::from_bytes(&invalid_bytes);
1420 assert!(result.is_err());
1421
1422 let invalid_bytes = vec![
1424 0xFF, 0x80, 0x00, 0xA1, ];
1428 let result = Decimal::from_bytes(&invalid_bytes);
1429 assert!(result.is_err());
1430
1431 let invalid_bytes = vec![
1433 0xFF, 0x80, 0x00, 0x1B, ];
1437 let result = Decimal::from_bytes(&invalid_bytes);
1438 assert!(result.is_err());
1439 }
1440
1441 #[test]
1442 fn test_reserved_exponent_positive() {
1443 let bytes_with_reserved_exp = vec![
1450 0xFF, 0xFF, 0xFF, 0x12, ];
1454 let result = Decimal::from_bytes(&bytes_with_reserved_exp);
1455 assert!(result.is_err());
1456
1457 let bytes_with_reserved_exp = vec![
1459 0xFF, 0xFF, 0xFE, 0x12, ];
1463 let result = Decimal::from_bytes(&bytes_with_reserved_exp);
1464 assert!(result.is_err());
1465 }
1466
1467 #[test]
1468 fn test_reserved_exponent_negative() {
1469 let bytes_with_reserved_exp = vec![
1474 0x00, 0x00, 0x00, 0x12, ];
1478 let result = Decimal::from_bytes(&bytes_with_reserved_exp);
1479 assert!(result.is_err());
1480 }
1481
1482 #[test]
1483 fn test_empty_mantissa_bytes() {
1484 let bytes_no_mantissa = vec![
1487 0xFF, 0x80, 0x00, ];
1491 let d = Decimal::from_bytes(&bytes_no_mantissa).unwrap();
1492 assert_eq!(d.to_string(), "0");
1493 }
1494
1495 #[cfg(feature = "rust_decimal")]
1498 mod rust_decimal_tests {
1499 use super::*;
1500
1501 #[test]
1502 fn test_from_rust_decimal() {
1503 use rust_decimal::Decimal as RustDecimal;
1504
1505 let rd = RustDecimal::new(12345, 2); let d: Decimal = rd.try_into().unwrap();
1507 assert_eq!(d.to_string(), "123.45");
1508 }
1509
1510 #[test]
1511 fn test_to_rust_decimal() {
1512 use rust_decimal::Decimal as RustDecimal;
1513
1514 let d = Decimal::from_str("123.45").unwrap();
1515 let rd: RustDecimal = (&d).try_into().unwrap();
1516 assert_eq!(rd.to_string(), "123.45");
1517 }
1518
1519 #[test]
1520 fn test_rust_decimal_roundtrip() {
1521 use rust_decimal::Decimal as RustDecimal;
1522
1523 let values = vec!["0", "1", "-1", "123.456", "-999.999", "0.001"];
1524
1525 for s in values {
1526 let d = Decimal::from_str(s).unwrap();
1527 let rd: RustDecimal = (&d).try_into().unwrap();
1528 let d2: Decimal = rd.try_into().unwrap();
1529 assert_eq!(d, d2, "Roundtrip failed for {}", s);
1530 }
1531 }
1532
1533 #[test]
1534 fn test_rust_decimal_arithmetic() {
1535 use rust_decimal::Decimal as RustDecimal;
1536
1537 let a = Decimal::from_str("100.50").unwrap();
1539 let b = Decimal::from_str("25.25").unwrap();
1540
1541 let ra: RustDecimal = (&a).try_into().unwrap();
1543 let rb: RustDecimal = (&b).try_into().unwrap();
1544 let sum = ra + rb;
1545
1546 let result: Decimal = sum.try_into().unwrap();
1548 assert_eq!(result.to_string(), "125.75");
1549 }
1550
1551 #[test]
1552 fn test_rust_decimal_from_owned() {
1553 use rust_decimal::Decimal as RustDecimal;
1554
1555 let d = Decimal::from_str("456.789").unwrap();
1557 let rd: RustDecimal = d.try_into().unwrap();
1558 assert_eq!(rd.to_string(), "456.789");
1559 }
1560
1561 #[test]
1562 fn test_rust_decimal_special_values_fail() {
1563 use rust_decimal::Decimal as RustDecimal;
1564
1565 let inf = Decimal::infinity();
1567 let result: Result<RustDecimal, _> = (&inf).try_into();
1568 assert!(result.is_err());
1569
1570 let nan = Decimal::nan();
1572 let result: Result<RustDecimal, _> = (&nan).try_into();
1573 assert!(result.is_err());
1574 }
1575 }
1576
1577 #[cfg(feature = "bigdecimal")]
1580 mod bigdecimal_tests {
1581 use super::*;
1582
1583 #[test]
1584 fn test_from_bigdecimal() {
1585 use bigdecimal::BigDecimal;
1586 use std::str::FromStr;
1587
1588 let bd = BigDecimal::from_str("123.45").unwrap();
1589 let d: Decimal = bd.try_into().unwrap();
1590 assert_eq!(d.to_string(), "123.45");
1591 }
1592
1593 #[test]
1594 fn test_to_bigdecimal() {
1595 use bigdecimal::BigDecimal;
1596
1597 let d = Decimal::from_str("123.45").unwrap();
1598 let bd: BigDecimal = (&d).try_into().unwrap();
1599 assert_eq!(bd.to_string(), "123.45");
1600 }
1601
1602 #[test]
1603 fn test_bigdecimal_roundtrip() {
1604 use bigdecimal::BigDecimal;
1605
1606 let values = vec!["0", "1", "-1", "123.456", "-999.999", "0.001"];
1607
1608 for s in values {
1609 let d = Decimal::from_str(s).unwrap();
1610 let bd: BigDecimal = (&d).try_into().unwrap();
1611 let d2: Decimal = bd.try_into().unwrap();
1612 assert_eq!(d, d2, "Roundtrip failed for {}", s);
1613 }
1614 }
1615
1616 #[test]
1617 fn test_bigdecimal_from_owned() {
1618 use bigdecimal::BigDecimal;
1619
1620 let d = Decimal::from_str("456.789").unwrap();
1622 let bd: BigDecimal = d.try_into().unwrap();
1623 assert_eq!(bd.to_string(), "456.789");
1624 }
1625
1626 #[test]
1627 fn test_bigdecimal_from_ref() {
1628 use bigdecimal::BigDecimal;
1629 use std::str::FromStr;
1630
1631 let bd = BigDecimal::from_str("789.012").unwrap();
1633 let d: Decimal = (&bd).try_into().unwrap();
1634 assert_eq!(d.to_string(), "789.012");
1635 }
1636
1637 #[test]
1638 fn test_bigdecimal_special_values_fail() {
1639 use bigdecimal::BigDecimal;
1640
1641 let inf = Decimal::infinity();
1643 let result: Result<BigDecimal, _> = (&inf).try_into();
1644 assert!(result.is_err());
1645
1646 let nan = Decimal::nan();
1648 let result: Result<BigDecimal, _> = (&nan).try_into();
1649 assert!(result.is_err());
1650 }
1651 }
1652}