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")
470 }
471 }
472 )*
473 };
474}
475
476impl_from_int!(i8, i16, i32, i64, i128, u8, u16, u32, u64, u128);
477
478impl Default for Decimal {
479 fn default() -> Self {
480 Decimal {
481 bytes: vec![encoding::SIGN_ZERO],
482 }
483 }
484}
485
486#[cfg(feature = "rust_decimal")]
491mod rust_decimal_interop {
492 use super::{Decimal, DecimalError};
493 use std::str::FromStr;
494
495 impl TryFrom<rust_decimal::Decimal> for Decimal {
496 type Error = DecimalError;
497
498 fn try_from(value: rust_decimal::Decimal) -> Result<Self, Self::Error> {
511 Decimal::from_str(&value.to_string())
512 }
513 }
514
515 impl TryFrom<&Decimal> for rust_decimal::Decimal {
516 type Error = rust_decimal::Error;
517
518 fn try_from(value: &Decimal) -> Result<Self, Self::Error> {
534 use std::str::FromStr;
535 rust_decimal::Decimal::from_str(&value.to_string())
536 }
537 }
538
539 impl TryFrom<Decimal> for rust_decimal::Decimal {
540 type Error = rust_decimal::Error;
541
542 fn try_from(value: Decimal) -> Result<Self, Self::Error> {
543 rust_decimal::Decimal::try_from(&value)
544 }
545 }
546}
547
548#[cfg(feature = "bigdecimal")]
556mod bigdecimal_interop {
557 use super::{Decimal, DecimalError};
558 use std::str::FromStr;
559
560 impl TryFrom<bigdecimal::BigDecimal> for Decimal {
561 type Error = DecimalError;
562
563 fn try_from(value: bigdecimal::BigDecimal) -> Result<Self, Self::Error> {
565 Decimal::from_str(&value.to_string())
566 }
567 }
568
569 impl TryFrom<&bigdecimal::BigDecimal> for Decimal {
570 type Error = DecimalError;
571
572 fn try_from(value: &bigdecimal::BigDecimal) -> Result<Self, Self::Error> {
573 Decimal::from_str(&value.to_string())
574 }
575 }
576
577 impl TryFrom<&Decimal> for bigdecimal::BigDecimal {
578 type Error = bigdecimal::ParseBigDecimalError;
579
580 fn try_from(value: &Decimal) -> Result<Self, Self::Error> {
585 use std::str::FromStr;
586 bigdecimal::BigDecimal::from_str(&value.to_string())
587 }
588 }
589
590 impl TryFrom<Decimal> for bigdecimal::BigDecimal {
591 type Error = bigdecimal::ParseBigDecimalError;
592
593 fn try_from(value: Decimal) -> Result<Self, Self::Error> {
594 bigdecimal::BigDecimal::try_from(&value)
595 }
596 }
597}
598
599#[cfg(test)]
603mod tests {
604 use super::*;
605
606 #[test]
607 fn test_from_str() {
608 let d = Decimal::from_str("123.456").unwrap();
609 assert_eq!(d.to_string(), "123.456");
610 }
611
612 #[test]
613 fn test_zero() {
614 let d = Decimal::from_str("0").unwrap();
615 assert!(d.is_zero());
616 assert!(!d.is_negative());
617 assert!(!d.is_positive());
618 assert!(d.is_finite());
619 assert!(!d.is_special());
620 }
621
622 #[test]
623 fn test_negative() {
624 let d = Decimal::from_str("-123.456").unwrap();
625 assert!(d.is_negative());
626 assert!(!d.is_zero());
627 assert!(!d.is_positive());
628 assert!(d.is_finite());
629 }
630
631 #[test]
632 fn test_positive() {
633 let d = Decimal::from_str("123.456").unwrap();
634 assert!(d.is_positive());
635 assert!(!d.is_zero());
636 assert!(!d.is_negative());
637 assert!(d.is_finite());
638 }
639
640 #[test]
641 fn test_ordering() {
642 let values = vec!["-100", "-10", "-1", "-0.1", "0", "0.1", "1", "10", "100"];
643 let decimals: Vec<Decimal> = values
644 .iter()
645 .map(|s| Decimal::from_str(s).unwrap())
646 .collect();
647
648 for i in 0..decimals.len() - 1 {
650 assert!(
651 decimals[i] < decimals[i + 1],
652 "{} should be < {}",
653 values[i],
654 values[i + 1]
655 );
656 }
657
658 for i in 0..decimals.len() - 1 {
660 assert!(
661 decimals[i].as_bytes() < decimals[i + 1].as_bytes(),
662 "bytes of {} should be < bytes of {}",
663 values[i],
664 values[i + 1]
665 );
666 }
667 }
668
669 #[test]
670 fn test_roundtrip() {
671 let values = vec![
672 "0", "1", "-1", "123.456", "-123.456", "0.001", "0.1", "10", "100", "1000000",
673 "-1000000",
674 ];
675
676 for s in values {
677 let d = Decimal::from_str(s).unwrap();
678 let bytes = d.as_bytes();
679 let restored = Decimal::from_bytes(bytes).unwrap();
680 assert_eq!(d, restored, "Roundtrip failed for {}", s);
681 }
682 }
683
684 #[test]
685 fn test_precision_scale() {
686 let d = Decimal::with_precision_scale("123.456", Some(10), Some(2)).unwrap();
688 assert_eq!(d.to_string(), "123.46");
689
690 let d = Decimal::with_precision_scale("12345.67", Some(5), Some(2)).unwrap();
692 assert_eq!(d.to_string(), "345.67"); let d = Decimal::with_precision_scale("99.999", Some(5), Some(2)).unwrap();
696 assert_eq!(d.to_string(), "100"); }
698
699 #[test]
700 fn test_from_integer() {
701 let d = Decimal::from(42i64);
702 assert_eq!(d.to_string(), "42");
703
704 let d = Decimal::from(-100i32);
705 assert_eq!(d.to_string(), "-100");
706 }
707
708 #[test]
709 fn test_serialization() {
710 let d = Decimal::from_str("123.456").unwrap();
711 let json = serde_json::to_string(&d).unwrap();
712 assert_eq!(json, "\"123.456\"");
713
714 let restored: Decimal = serde_json::from_str(&json).unwrap();
715 assert_eq!(d, restored);
716 }
717
718 #[test]
719 fn test_byte_efficiency() {
720 let d = Decimal::from_str("123456789").unwrap();
722 assert!(
724 d.byte_len() <= 10,
725 "Expected <= 10 bytes, got {}",
726 d.byte_len()
727 );
728
729 let d = Decimal::from_str("0.000001").unwrap();
730 assert!(
732 d.byte_len() <= 6,
733 "Expected <= 6 bytes, got {}",
734 d.byte_len()
735 );
736 }
737
738 #[test]
741 fn test_infinity_creation() {
742 let pos_inf = Decimal::infinity();
743 assert!(pos_inf.is_pos_infinity());
744 assert!(pos_inf.is_infinity());
745 assert!(!pos_inf.is_neg_infinity());
746 assert!(!pos_inf.is_nan());
747 assert!(pos_inf.is_special());
748 assert!(!pos_inf.is_finite());
749 assert_eq!(pos_inf.to_string(), "Infinity");
750
751 let neg_inf = Decimal::neg_infinity();
752 assert!(neg_inf.is_neg_infinity());
753 assert!(neg_inf.is_infinity());
754 assert!(!neg_inf.is_pos_infinity());
755 assert!(!neg_inf.is_nan());
756 assert!(neg_inf.is_special());
757 assert!(!neg_inf.is_finite());
758 assert_eq!(neg_inf.to_string(), "-Infinity");
759 }
760
761 #[test]
762 fn test_nan_creation() {
763 let nan = Decimal::nan();
764 assert!(nan.is_nan());
765 assert!(nan.is_special());
766 assert!(!nan.is_finite());
767 assert!(!nan.is_infinity());
768 assert!(!nan.is_zero());
769 assert_eq!(nan.to_string(), "NaN");
770 }
771
772 #[test]
773 fn test_special_value_from_str() {
774 let pos_inf = Decimal::from_str("Infinity").unwrap();
775 assert!(pos_inf.is_pos_infinity());
776
777 let neg_inf = Decimal::from_str("-Infinity").unwrap();
778 assert!(neg_inf.is_neg_infinity());
779
780 let nan = Decimal::from_str("NaN").unwrap();
781 assert!(nan.is_nan());
782
783 let inf = Decimal::from_str("infinity").unwrap();
785 assert!(inf.is_pos_infinity());
786
787 let inf = Decimal::from_str("INF").unwrap();
788 assert!(inf.is_pos_infinity());
789 }
790
791 #[test]
792 fn test_special_value_ordering() {
793 let neg_inf = Decimal::neg_infinity();
795 let neg_num = Decimal::from_str("-1000").unwrap();
796 let zero = Decimal::from_str("0").unwrap();
797 let pos_num = Decimal::from_str("1000").unwrap();
798 let pos_inf = Decimal::infinity();
799 let nan = Decimal::nan();
800
801 assert!(neg_inf < neg_num);
802 assert!(neg_num < zero);
803 assert!(zero < pos_num);
804 assert!(pos_num < pos_inf);
805 assert!(pos_inf < nan);
806
807 assert!(neg_inf.as_bytes() < neg_num.as_bytes());
809 assert!(neg_num.as_bytes() < zero.as_bytes());
810 assert!(zero.as_bytes() < pos_num.as_bytes());
811 assert!(pos_num.as_bytes() < pos_inf.as_bytes());
812 assert!(pos_inf.as_bytes() < nan.as_bytes());
813 }
814
815 #[test]
816 fn test_special_value_equality() {
817 let nan1 = Decimal::from_str("NaN").unwrap();
819 let nan2 = Decimal::from_str("nan").unwrap();
820 let nan3 = Decimal::nan();
821 assert_eq!(nan1, nan2);
822 assert_eq!(nan2, nan3);
823
824 let inf1 = Decimal::infinity();
826 let inf2 = Decimal::from_str("Infinity").unwrap();
827 assert_eq!(inf1, inf2);
828
829 let neg_inf1 = Decimal::neg_infinity();
830 let neg_inf2 = Decimal::from_str("-Infinity").unwrap();
831 assert_eq!(neg_inf1, neg_inf2);
832 }
833
834 #[test]
835 fn test_special_value_serialization() {
836 let inf = Decimal::infinity();
837 let json = serde_json::to_string(&inf).unwrap();
838 assert_eq!(json, "\"Infinity\"");
839 let restored: Decimal = serde_json::from_str(&json).unwrap();
840 assert_eq!(inf, restored);
841
842 let nan = Decimal::nan();
843 let json = serde_json::to_string(&nan).unwrap();
844 assert_eq!(json, "\"NaN\"");
845 let restored: Decimal = serde_json::from_str(&json).unwrap();
846 assert_eq!(nan, restored);
847 }
848
849 #[test]
850 fn test_special_value_byte_efficiency() {
851 assert_eq!(Decimal::infinity().byte_len(), 3);
853 assert_eq!(Decimal::neg_infinity().byte_len(), 3);
854 assert_eq!(Decimal::nan().byte_len(), 3);
855 }
856
857 #[test]
860 fn test_negative_scale() {
861 let d = Decimal::with_precision_scale("12345", Some(10), Some(-3)).unwrap();
863 assert_eq!(d.to_string(), "12000");
864
865 let d = Decimal::with_precision_scale("12500", Some(10), Some(-3)).unwrap();
867 assert_eq!(d.to_string(), "13000");
868
869 let d = Decimal::with_precision_scale("1234", Some(10), Some(-2)).unwrap();
871 assert_eq!(d.to_string(), "1200");
872 }
873
874 #[test]
875 fn test_negative_scale_with_precision() {
876 let d = Decimal::with_precision_scale("12345", Some(2), Some(-3)).unwrap();
878 assert_eq!(d.to_string(), "12000");
879 }
880
881 #[test]
884 fn test_invalid_format_errors() {
885 let result = Decimal::from_str("1.2.3");
887 assert!(result.is_err());
888 assert!(matches!(
889 result.unwrap_err(),
890 DecimalError::InvalidFormat(_)
891 ));
892
893 let result = Decimal::from_str("12abc");
895 assert!(result.is_err());
896
897 let result = Decimal::from_str("1e");
899 assert!(result.is_err());
900 assert!(matches!(
901 result.unwrap_err(),
902 DecimalError::InvalidFormat(_)
903 ));
904
905 let result = Decimal::from_str("1eabc");
907 assert!(result.is_err());
908
909 let d = Decimal::from_str("").unwrap();
911 assert!(d.is_zero());
912
913 let result = Decimal::from_str("-");
915 assert!(result.is_ok()); }
917
918 #[test]
919 fn test_leading_plus_sign() {
920 let d = Decimal::from_str("+123.456").unwrap();
921 assert_eq!(d.to_string(), "123.456");
922 assert!(d.is_positive());
923 }
924
925 #[test]
926 fn test_scientific_notation() {
927 let d = Decimal::from_str("1.5e10").unwrap();
928 assert_eq!(d.to_string(), "15000000000");
929
930 let d = Decimal::from_str("1.5E-3").unwrap();
931 assert_eq!(d.to_string(), "0.0015");
932
933 let d = Decimal::from_str("1e+5").unwrap();
934 assert_eq!(d.to_string(), "100000");
935 }
936
937 #[test]
938 fn test_leading_decimal_point() {
939 let d = Decimal::from_str(".5").unwrap();
941 assert_eq!(d.to_string(), "0.5");
942
943 let d = Decimal::from_str("-.25").unwrap();
944 assert_eq!(d.to_string(), "-0.25");
945 }
946
947 #[test]
948 fn test_trailing_zeros() {
949 let d = Decimal::from_str("100").unwrap();
950 assert_eq!(d.to_string(), "100");
951
952 let d = Decimal::from_str("1.500").unwrap();
953 assert_eq!(d.to_string(), "1.5");
954 }
955
956 #[test]
957 fn test_leading_zeros() {
958 let d = Decimal::from_str("007").unwrap();
959 assert_eq!(d.to_string(), "7");
960
961 let d = Decimal::from_str("00.123").unwrap();
962 assert_eq!(d.to_string(), "0.123");
963 }
964
965 #[test]
968 fn test_into_bytes() {
969 let d = Decimal::from_str("123.456").unwrap();
970 let bytes_ref = d.as_bytes().to_vec();
971 let bytes_owned = d.into_bytes();
972 assert_eq!(bytes_ref, bytes_owned);
973 }
974
975 #[test]
976 fn test_clone() {
977 let d1 = Decimal::from_str("123.456").unwrap();
978 let d2 = d1.clone();
979 assert_eq!(d1, d2);
980 assert_eq!(d1.as_bytes(), d2.as_bytes());
981 }
982
983 #[test]
984 fn test_hash() {
985 use std::collections::HashSet;
986
987 let mut set = HashSet::new();
988 set.insert(Decimal::from_str("123.456").unwrap());
989 set.insert(Decimal::from_str("123.456").unwrap()); set.insert(Decimal::from_str("789.012").unwrap());
991
992 assert_eq!(set.len(), 2);
993 assert!(set.contains(&Decimal::from_str("123.456").unwrap()));
994 }
995
996 #[test]
997 fn test_debug_format() {
998 let d = Decimal::from_str("123.456").unwrap();
999 let debug_str = format!("{:?}", d);
1000 assert!(debug_str.contains("Decimal"));
1001 assert!(debug_str.contains("123.456"));
1002 }
1003
1004 #[test]
1005 fn test_ord_trait() {
1006 use std::cmp::Ordering;
1007
1008 let a = Decimal::from_str("1").unwrap();
1009 let b = Decimal::from_str("2").unwrap();
1010 let c = Decimal::from_str("1").unwrap();
1011
1012 assert_eq!(a.cmp(&b), Ordering::Less);
1013 assert_eq!(b.cmp(&a), Ordering::Greater);
1014 assert_eq!(a.cmp(&c), Ordering::Equal);
1015 }
1016
1017 #[test]
1018 fn test_from_bytes_invalid() {
1019 let result = Decimal::from_bytes(&[]);
1021 assert!(result.is_err());
1022
1023 let result = Decimal::from_bytes(&[0x00]);
1025 assert!(result.is_err());
1026 }
1027
1028 #[test]
1029 fn test_deserialize_from_string_number() {
1030 let d: Decimal = serde_json::from_str("\"42\"").unwrap();
1032 assert_eq!(d.to_string(), "42");
1033
1034 let d: Decimal = serde_json::from_str("\"-100\"").unwrap();
1035 assert_eq!(d.to_string(), "-100");
1036
1037 let d: Decimal = serde_json::from_str("\"1.5e10\"").unwrap();
1038 assert_eq!(d.to_string(), "15000000000");
1039 }
1040
1041 #[test]
1042 fn test_from_various_integer_types() {
1043 assert_eq!(Decimal::from(0i32).to_string(), "0");
1044 assert_eq!(Decimal::from(i32::MAX).to_string(), "2147483647");
1045 assert_eq!(Decimal::from(i32::MIN).to_string(), "-2147483648");
1046 assert_eq!(Decimal::from(i64::MAX).to_string(), "9223372036854775807");
1047 assert_eq!(Decimal::from(i64::MIN).to_string(), "-9223372036854775808");
1048 }
1049
1050 #[test]
1051 fn test_precision_overflow() {
1052 let result = Decimal::from_str("1e20000");
1054 assert!(result.is_err());
1055 assert!(matches!(
1056 result.unwrap_err(),
1057 DecimalError::PrecisionOverflow
1058 ));
1059
1060 let result = Decimal::from_str("1e-20000");
1062 assert!(result.is_err());
1063 assert!(matches!(
1064 result.unwrap_err(),
1065 DecimalError::PrecisionOverflow
1066 ));
1067 }
1068
1069 #[test]
1070 fn test_all_zeros_variations() {
1071 let d = Decimal::from_str("0").unwrap();
1072 assert!(d.is_zero());
1073
1074 let d = Decimal::from_str("0.0").unwrap();
1075 assert!(d.is_zero());
1076
1077 let d = Decimal::from_str("00.00").unwrap();
1078 assert!(d.is_zero());
1079
1080 let d = Decimal::from_str("-0").unwrap();
1081 assert!(d.is_zero());
1082 }
1084
1085 #[test]
1088 fn test_rounding_all_nines() {
1089 let d = Decimal::with_precision_scale("99.999", Some(10), Some(2)).unwrap();
1091 assert_eq!(d.to_string(), "100");
1092
1093 let d = Decimal::with_precision_scale("9.99", Some(10), Some(1)).unwrap();
1095 assert_eq!(d.to_string(), "10");
1096
1097 let d = Decimal::with_precision_scale("999", Some(10), Some(-1)).unwrap();
1099 assert_eq!(d.to_string(), "1000");
1100 }
1101
1102 #[test]
1103 fn test_negative_scale_small_number() {
1104 let d = Decimal::with_precision_scale("4", Some(10), Some(-1)).unwrap();
1106 assert_eq!(d.to_string(), "0");
1107
1108 let d = Decimal::with_precision_scale("5", Some(10), Some(-1)).unwrap();
1110 assert_eq!(d.to_string(), "10");
1111
1112 let d = Decimal::with_precision_scale("-4", Some(10), Some(-1)).unwrap();
1114 assert_eq!(d.to_string(), "0");
1115
1116 let d = Decimal::with_precision_scale("-5", Some(10), Some(-1)).unwrap();
1118 assert_eq!(d.to_string(), "-10");
1119 }
1120
1121 #[test]
1122 fn test_precision_truncation() {
1123 let d = Decimal::with_precision_scale("123456", Some(3), Some(0)).unwrap();
1125 assert_eq!(d.to_string(), "456");
1126
1127 let d = Decimal::with_precision_scale("12345.67", Some(4), Some(2)).unwrap();
1129 assert_eq!(d.to_string(), "45.67");
1130 }
1131
1132 #[test]
1133 fn test_very_small_numbers() {
1134 let d = Decimal::from_str("0.000000001").unwrap();
1135 assert_eq!(d.to_string(), "0.000000001");
1136 assert!(d.is_positive());
1137
1138 let d = Decimal::from_str("-0.000000001").unwrap();
1139 assert_eq!(d.to_string(), "-0.000000001");
1140 assert!(d.is_negative());
1141 }
1142
1143 #[test]
1144 fn test_very_large_numbers() {
1145 let d = Decimal::from_str("999999999999999999999999999999").unwrap();
1146 assert_eq!(d.to_string(), "999999999999999999999999999999");
1147
1148 let d = Decimal::from_str("-999999999999999999999999999999").unwrap();
1149 assert_eq!(d.to_string(), "-999999999999999999999999999999");
1150 }
1151
1152 #[test]
1153 fn test_max_exponent_boundary() {
1154 let d = Decimal::from_str("1e16000").unwrap();
1156 assert!(d.is_positive());
1157
1158 let result = Decimal::from_str("1e17000");
1160 assert!(result.is_err());
1161 }
1162
1163 #[test]
1164 fn test_min_exponent_boundary() {
1165 let d = Decimal::from_str("1e-16000").unwrap();
1167 assert!(d.is_positive());
1168
1169 let result = Decimal::from_str("1e-17000");
1171 assert!(result.is_err());
1172 }
1173
1174 #[test]
1175 fn test_odd_digit_count() {
1176 let d = Decimal::from_str("12345").unwrap();
1178 assert_eq!(d.to_string(), "12345");
1179
1180 let d = Decimal::from_str("1").unwrap();
1181 assert_eq!(d.to_string(), "1");
1182
1183 let d = Decimal::from_str("123").unwrap();
1184 assert_eq!(d.to_string(), "123");
1185 }
1186
1187 #[test]
1188 fn test_negative_number_ordering() {
1189 let a = Decimal::from_str("-100").unwrap();
1191 let b = Decimal::from_str("-10").unwrap();
1192 let c = Decimal::from_str("-1").unwrap();
1193
1194 assert!(a < b);
1196 assert!(b < c);
1197
1198 assert!(a.as_bytes() < b.as_bytes());
1200 assert!(b.as_bytes() < c.as_bytes());
1201 }
1202
1203 #[test]
1204 fn test_from_bytes_unchecked_roundtrip() {
1205 let original = Decimal::from_str("123.456").unwrap();
1206 let bytes = original.as_bytes().to_vec();
1207 let restored = Decimal::from_bytes_unchecked(bytes);
1208 assert_eq!(original, restored);
1209 }
1210
1211 #[test]
1212 fn test_special_value_checks() {
1213 let d = Decimal::from_str("123.456").unwrap();
1214 assert!(!d.is_nan());
1215 assert!(!d.is_infinity());
1216 assert!(!d.is_pos_infinity());
1217 assert!(!d.is_neg_infinity());
1218 assert!(!d.is_special());
1219 assert!(d.is_finite());
1220 }
1221
1222 #[test]
1223 fn test_equality_and_hash_consistency() {
1224 use std::collections::HashMap;
1225
1226 let d1 = Decimal::from_str("123.456").unwrap();
1227 let d2 = Decimal::from_str("123.456").unwrap();
1228 let d3 = Decimal::from_str("123.457").unwrap();
1229
1230 assert_eq!(d1, d2);
1232 assert_ne!(d1, d3);
1233
1234 let mut map = HashMap::new();
1236 map.insert(d1.clone(), "first");
1237 map.insert(d2.clone(), "second"); assert_eq!(map.len(), 1);
1239 assert_eq!(map.get(&d1), Some(&"second"));
1240 }
1241
1242 #[test]
1243 fn test_scale_zero() {
1244 let d = Decimal::with_precision_scale("123.999", Some(10), Some(0)).unwrap();
1246 assert_eq!(d.to_string(), "124"); }
1248
1249 #[test]
1250 fn test_only_fractional_with_precision_scale() {
1251 let d = Decimal::with_precision_scale(".5", Some(10), Some(2)).unwrap();
1252 assert_eq!(d.to_string(), "0.5");
1253 }
1254
1255 #[test]
1256 fn test_default_impl() {
1257 let d = Decimal::default();
1258 assert!(d.is_zero());
1259 assert_eq!(d.to_string(), "0");
1260 }
1261
1262 #[test]
1263 fn test_precision_zero_integer_digits() {
1264 let d = Decimal::with_precision_scale("123.456", Some(2), Some(2)).unwrap();
1267 assert_eq!(d.to_string(), "0.46");
1268 }
1269
1270 #[test]
1271 fn test_negative_with_precision_truncation() {
1272 let d = Decimal::with_precision_scale("-123.456", Some(3), Some(2)).unwrap();
1274 assert_eq!(d.to_string(), "-3.46");
1275 }
1276
1277 #[test]
1278 fn test_invalid_sign_byte() {
1279 let result = Decimal::from_bytes(&[0x01, 0x40, 0x00, 0x12]);
1284 assert!(result.is_err());
1285
1286 let result = Decimal::from_bytes(&[0x7F, 0x40, 0x00, 0x12]);
1288 assert!(result.is_err());
1289
1290 let result = Decimal::from_bytes(&[0xFE, 0x40, 0x00, 0x12]);
1292 assert!(result.is_err());
1293 }
1294
1295 #[test]
1296 fn test_invalid_bcd_encoding() {
1297 let invalid_bytes = vec![
1301 0xFF, 0x80, 0x00, 0xAB, ];
1305 let result = Decimal::from_bytes(&invalid_bytes);
1306 assert!(result.is_err());
1307
1308 let invalid_bytes = vec![
1310 0xFF, 0x80, 0x00, 0xA1, ];
1314 let result = Decimal::from_bytes(&invalid_bytes);
1315 assert!(result.is_err());
1316
1317 let invalid_bytes = vec![
1319 0xFF, 0x80, 0x00, 0x1B, ];
1323 let result = Decimal::from_bytes(&invalid_bytes);
1324 assert!(result.is_err());
1325 }
1326
1327 #[test]
1328 fn test_reserved_exponent_positive() {
1329 let bytes_with_reserved_exp = vec![
1336 0xFF, 0xFF, 0xFF, 0x12, ];
1340 let result = Decimal::from_bytes(&bytes_with_reserved_exp);
1341 assert!(result.is_err());
1342
1343 let bytes_with_reserved_exp = vec![
1345 0xFF, 0xFF, 0xFE, 0x12, ];
1349 let result = Decimal::from_bytes(&bytes_with_reserved_exp);
1350 assert!(result.is_err());
1351 }
1352
1353 #[test]
1354 fn test_reserved_exponent_negative() {
1355 let bytes_with_reserved_exp = vec![
1360 0x00, 0x00, 0x00, 0x12, ];
1364 let result = Decimal::from_bytes(&bytes_with_reserved_exp);
1365 assert!(result.is_err());
1366 }
1367
1368 #[test]
1369 fn test_empty_mantissa_bytes() {
1370 let bytes_no_mantissa = vec![
1373 0xFF, 0x80, 0x00, ];
1377 let d = Decimal::from_bytes(&bytes_no_mantissa).unwrap();
1378 assert_eq!(d.to_string(), "0");
1379 }
1380
1381 #[cfg(feature = "rust_decimal")]
1384 mod rust_decimal_tests {
1385 use super::*;
1386
1387 #[test]
1388 fn test_from_rust_decimal() {
1389 use rust_decimal::Decimal as RustDecimal;
1390
1391 let rd = RustDecimal::new(12345, 2); let d: Decimal = rd.try_into().unwrap();
1393 assert_eq!(d.to_string(), "123.45");
1394 }
1395
1396 #[test]
1397 fn test_to_rust_decimal() {
1398 use rust_decimal::Decimal as RustDecimal;
1399
1400 let d = Decimal::from_str("123.45").unwrap();
1401 let rd: RustDecimal = (&d).try_into().unwrap();
1402 assert_eq!(rd.to_string(), "123.45");
1403 }
1404
1405 #[test]
1406 fn test_rust_decimal_roundtrip() {
1407 use rust_decimal::Decimal as RustDecimal;
1408
1409 let values = vec!["0", "1", "-1", "123.456", "-999.999", "0.001"];
1410
1411 for s in values {
1412 let d = Decimal::from_str(s).unwrap();
1413 let rd: RustDecimal = (&d).try_into().unwrap();
1414 let d2: Decimal = rd.try_into().unwrap();
1415 assert_eq!(d, d2, "Roundtrip failed for {}", s);
1416 }
1417 }
1418
1419 #[test]
1420 fn test_rust_decimal_arithmetic() {
1421 use rust_decimal::Decimal as RustDecimal;
1422
1423 let a = Decimal::from_str("100.50").unwrap();
1425 let b = Decimal::from_str("25.25").unwrap();
1426
1427 let ra: RustDecimal = (&a).try_into().unwrap();
1429 let rb: RustDecimal = (&b).try_into().unwrap();
1430 let sum = ra + rb;
1431
1432 let result: Decimal = sum.try_into().unwrap();
1434 assert_eq!(result.to_string(), "125.75");
1435 }
1436
1437 #[test]
1438 fn test_rust_decimal_from_owned() {
1439 use rust_decimal::Decimal as RustDecimal;
1440
1441 let d = Decimal::from_str("456.789").unwrap();
1443 let rd: RustDecimal = d.try_into().unwrap();
1444 assert_eq!(rd.to_string(), "456.789");
1445 }
1446
1447 #[test]
1448 fn test_rust_decimal_special_values_fail() {
1449 use rust_decimal::Decimal as RustDecimal;
1450
1451 let inf = Decimal::infinity();
1453 let result: Result<RustDecimal, _> = (&inf).try_into();
1454 assert!(result.is_err());
1455
1456 let nan = Decimal::nan();
1458 let result: Result<RustDecimal, _> = (&nan).try_into();
1459 assert!(result.is_err());
1460 }
1461 }
1462
1463 #[cfg(feature = "bigdecimal")]
1466 mod bigdecimal_tests {
1467 use super::*;
1468
1469 #[test]
1470 fn test_from_bigdecimal() {
1471 use bigdecimal::BigDecimal;
1472 use std::str::FromStr;
1473
1474 let bd = BigDecimal::from_str("123.45").unwrap();
1475 let d: Decimal = bd.try_into().unwrap();
1476 assert_eq!(d.to_string(), "123.45");
1477 }
1478
1479 #[test]
1480 fn test_to_bigdecimal() {
1481 use bigdecimal::BigDecimal;
1482
1483 let d = Decimal::from_str("123.45").unwrap();
1484 let bd: BigDecimal = (&d).try_into().unwrap();
1485 assert_eq!(bd.to_string(), "123.45");
1486 }
1487
1488 #[test]
1489 fn test_bigdecimal_roundtrip() {
1490 use bigdecimal::BigDecimal;
1491
1492 let values = vec!["0", "1", "-1", "123.456", "-999.999", "0.001"];
1493
1494 for s in values {
1495 let d = Decimal::from_str(s).unwrap();
1496 let bd: BigDecimal = (&d).try_into().unwrap();
1497 let d2: Decimal = bd.try_into().unwrap();
1498 assert_eq!(d, d2, "Roundtrip failed for {}", s);
1499 }
1500 }
1501
1502 #[test]
1503 fn test_bigdecimal_from_owned() {
1504 use bigdecimal::BigDecimal;
1505
1506 let d = Decimal::from_str("456.789").unwrap();
1508 let bd: BigDecimal = d.try_into().unwrap();
1509 assert_eq!(bd.to_string(), "456.789");
1510 }
1511
1512 #[test]
1513 fn test_bigdecimal_from_ref() {
1514 use bigdecimal::BigDecimal;
1515 use std::str::FromStr;
1516
1517 let bd = BigDecimal::from_str("789.012").unwrap();
1519 let d: Decimal = (&bd).try_into().unwrap();
1520 assert_eq!(d.to_string(), "789.012");
1521 }
1522
1523 #[test]
1524 fn test_bigdecimal_special_values_fail() {
1525 use bigdecimal::BigDecimal;
1526
1527 let inf = Decimal::infinity();
1529 let result: Result<BigDecimal, _> = (&inf).try_into();
1530 assert!(result.is_err());
1531
1532 let nan = Decimal::nan();
1534 let result: Result<BigDecimal, _> = (&nan).try_into();
1535 assert!(result.is_err());
1536 }
1537 }
1538}