1mod decimal64;
103mod encoding;
104
105use std::cmp::Ordering;
106use std::fmt;
107use std::hash::{Hash, Hasher};
108use std::str::FromStr;
109
110use serde::{Deserialize, Deserializer, Serialize, Serializer};
111
112pub use decimal64::{Decimal64, MAX_DECIMAL64_PRECISION, MAX_DECIMAL64_SCALE};
113pub use encoding::DecimalError;
114pub use encoding::SpecialValue;
115use encoding::{
116 decode_special_value, decode_to_string, encode_decimal, encode_decimal_with_constraints,
117 encode_special_value, ENCODING_NAN, ENCODING_NEG_INFINITY, ENCODING_POS_INFINITY,
118};
119
120#[derive(Clone)]
133pub struct Decimal {
134 bytes: Vec<u8>,
135}
136
137impl Decimal {
138 pub fn with_precision_scale(
166 s: &str,
167 precision: Option<u32>,
168 scale: Option<i32>,
169 ) -> Result<Self, DecimalError> {
170 let bytes = encode_decimal_with_constraints(s, precision, scale)?;
171 Ok(Self { bytes })
172 }
173
174 pub fn from_bytes(bytes: &[u8]) -> Result<Self, DecimalError> {
191 let _ = decode_to_string(bytes)?;
193 Ok(Self {
194 bytes: bytes.to_vec(),
195 })
196 }
197
198 #[inline]
205 pub fn from_bytes_unchecked(bytes: Vec<u8>) -> Self {
206 Self { bytes }
207 }
208
209 #[inline]
214 pub fn as_bytes(&self) -> &[u8] {
215 &self.bytes
216 }
217
218 #[inline]
220 pub fn into_bytes(self) -> Vec<u8> {
221 self.bytes
222 }
223
224 pub fn is_zero(&self) -> bool {
226 self.bytes.len() == 1 && self.bytes[0] == encoding::SIGN_ZERO
227 }
228
229 pub fn is_negative(&self) -> bool {
231 !self.bytes.is_empty() && self.bytes[0] == encoding::SIGN_NEGATIVE
232 }
233
234 pub fn is_positive(&self) -> bool {
236 !self.bytes.is_empty() && self.bytes[0] == encoding::SIGN_POSITIVE
237 }
238
239 pub fn is_pos_infinity(&self) -> bool {
241 self.bytes.as_slice() == ENCODING_POS_INFINITY
242 }
243
244 pub fn is_neg_infinity(&self) -> bool {
246 self.bytes.as_slice() == ENCODING_NEG_INFINITY
247 }
248
249 pub fn is_infinity(&self) -> bool {
251 self.is_pos_infinity() || self.is_neg_infinity()
252 }
253
254 pub fn is_nan(&self) -> bool {
256 self.bytes.as_slice() == ENCODING_NAN
257 }
258
259 pub fn is_special(&self) -> bool {
261 decode_special_value(&self.bytes).is_some()
262 }
263
264 pub fn is_finite(&self) -> bool {
266 !self.is_special()
267 }
268
269 #[inline]
271 pub fn byte_len(&self) -> usize {
272 self.bytes.len()
273 }
274
275 pub fn infinity() -> Self {
292 Self {
293 bytes: encode_special_value(SpecialValue::Infinity),
294 }
295 }
296
297 pub fn neg_infinity() -> Self {
314 Self {
315 bytes: encode_special_value(SpecialValue::NegInfinity),
316 }
317 }
318
319 pub fn nan() -> Self {
348 Self {
349 bytes: encode_special_value(SpecialValue::NaN),
350 }
351 }
352}
353
354impl FromStr for Decimal {
355 type Err = DecimalError;
356
357 fn from_str(s: &str) -> Result<Self, Self::Err> {
372 let bytes = encode_decimal(s)?;
373 Ok(Self { bytes })
374 }
375}
376
377impl fmt::Display for Decimal {
378 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
379 let s = decode_to_string(&self.bytes).expect("Decimal contains valid bytes");
380 write!(f, "{}", s)
381 }
382}
383
384impl fmt::Debug for Decimal {
385 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
386 let value = decode_to_string(&self.bytes).expect("Decimal contains valid bytes");
387 f.debug_struct("Decimal")
388 .field("value", &value)
389 .field("bytes", &self.bytes)
390 .finish()
391 }
392}
393
394impl PartialEq for Decimal {
395 fn eq(&self, other: &Self) -> bool {
396 self.bytes == other.bytes
397 }
398}
399
400impl Eq for Decimal {}
401
402impl PartialOrd for Decimal {
403 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
404 Some(self.cmp(other))
405 }
406}
407
408impl Ord for Decimal {
409 fn cmp(&self, other: &Self) -> Ordering {
410 self.bytes.cmp(&other.bytes)
412 }
413}
414
415impl Hash for Decimal {
416 fn hash<H: Hasher>(&self, state: &mut H) {
417 self.bytes.hash(state);
418 }
419}
420
421impl Serialize for Decimal {
422 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
423 where
424 S: Serializer,
425 {
426 serializer.serialize_str(&self.to_string())
428 }
429}
430
431impl<'de> Deserialize<'de> for Decimal {
432 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
433 where
434 D: Deserializer<'de>,
435 {
436 let s = String::deserialize(deserializer)?;
437 Decimal::from_str(&s).map_err(serde::de::Error::custom)
438 }
439}
440
441macro_rules! impl_from_int {
443 ($($t:ty),*) => {
444 $(
445 impl From<$t> for Decimal {
446 fn from(val: $t) -> Self {
447 Decimal::from_str(&val.to_string()).expect("Integer is always valid")
448 }
449 }
450 )*
451 };
452}
453
454impl_from_int!(i8, i16, i32, i64, i128, u8, u16, u32, u64, u128);
455
456impl Default for Decimal {
457 fn default() -> Self {
458 Decimal {
459 bytes: vec![encoding::SIGN_ZERO],
460 }
461 }
462}
463
464#[cfg(feature = "rust_decimal")]
469mod rust_decimal_interop {
470 use super::{Decimal, DecimalError};
471 use std::str::FromStr;
472
473 impl TryFrom<rust_decimal::Decimal> for Decimal {
474 type Error = DecimalError;
475
476 fn try_from(value: rust_decimal::Decimal) -> Result<Self, Self::Error> {
489 Decimal::from_str(&value.to_string())
490 }
491 }
492
493 impl TryFrom<&Decimal> for rust_decimal::Decimal {
494 type Error = rust_decimal::Error;
495
496 fn try_from(value: &Decimal) -> Result<Self, Self::Error> {
512 use std::str::FromStr;
513 rust_decimal::Decimal::from_str(&value.to_string())
514 }
515 }
516
517 impl TryFrom<Decimal> for rust_decimal::Decimal {
518 type Error = rust_decimal::Error;
519
520 fn try_from(value: Decimal) -> Result<Self, Self::Error> {
521 rust_decimal::Decimal::try_from(&value)
522 }
523 }
524}
525
526#[cfg(feature = "bigdecimal")]
534mod bigdecimal_interop {
535 use super::{Decimal, DecimalError};
536 use std::str::FromStr;
537
538 impl TryFrom<bigdecimal::BigDecimal> for Decimal {
539 type Error = DecimalError;
540
541 fn try_from(value: bigdecimal::BigDecimal) -> Result<Self, Self::Error> {
543 Decimal::from_str(&value.to_string())
544 }
545 }
546
547 impl TryFrom<&bigdecimal::BigDecimal> for Decimal {
548 type Error = DecimalError;
549
550 fn try_from(value: &bigdecimal::BigDecimal) -> Result<Self, Self::Error> {
551 Decimal::from_str(&value.to_string())
552 }
553 }
554
555 impl TryFrom<&Decimal> for bigdecimal::BigDecimal {
556 type Error = bigdecimal::ParseBigDecimalError;
557
558 fn try_from(value: &Decimal) -> Result<Self, Self::Error> {
563 use std::str::FromStr;
564 bigdecimal::BigDecimal::from_str(&value.to_string())
565 }
566 }
567
568 impl TryFrom<Decimal> for bigdecimal::BigDecimal {
569 type Error = bigdecimal::ParseBigDecimalError;
570
571 fn try_from(value: Decimal) -> Result<Self, Self::Error> {
572 bigdecimal::BigDecimal::try_from(&value)
573 }
574 }
575}
576
577#[cfg(test)]
581mod tests {
582 use super::*;
583
584 #[test]
585 fn test_from_str() {
586 let d = Decimal::from_str("123.456").unwrap();
587 assert_eq!(d.to_string(), "123.456");
588 }
589
590 #[test]
591 fn test_zero() {
592 let d = Decimal::from_str("0").unwrap();
593 assert!(d.is_zero());
594 assert!(!d.is_negative());
595 assert!(!d.is_positive());
596 assert!(d.is_finite());
597 assert!(!d.is_special());
598 }
599
600 #[test]
601 fn test_negative() {
602 let d = Decimal::from_str("-123.456").unwrap();
603 assert!(d.is_negative());
604 assert!(!d.is_zero());
605 assert!(!d.is_positive());
606 assert!(d.is_finite());
607 }
608
609 #[test]
610 fn test_positive() {
611 let d = Decimal::from_str("123.456").unwrap();
612 assert!(d.is_positive());
613 assert!(!d.is_zero());
614 assert!(!d.is_negative());
615 assert!(d.is_finite());
616 }
617
618 #[test]
619 fn test_ordering() {
620 let values = vec!["-100", "-10", "-1", "-0.1", "0", "0.1", "1", "10", "100"];
621 let decimals: Vec<Decimal> = values
622 .iter()
623 .map(|s| Decimal::from_str(s).unwrap())
624 .collect();
625
626 for i in 0..decimals.len() - 1 {
628 assert!(
629 decimals[i] < decimals[i + 1],
630 "{} should be < {}",
631 values[i],
632 values[i + 1]
633 );
634 }
635
636 for i in 0..decimals.len() - 1 {
638 assert!(
639 decimals[i].as_bytes() < decimals[i + 1].as_bytes(),
640 "bytes of {} should be < bytes of {}",
641 values[i],
642 values[i + 1]
643 );
644 }
645 }
646
647 #[test]
648 fn test_roundtrip() {
649 let values = vec![
650 "0", "1", "-1", "123.456", "-123.456", "0.001", "0.1", "10", "100", "1000000",
651 "-1000000",
652 ];
653
654 for s in values {
655 let d = Decimal::from_str(s).unwrap();
656 let bytes = d.as_bytes();
657 let restored = Decimal::from_bytes(bytes).unwrap();
658 assert_eq!(d, restored, "Roundtrip failed for {}", s);
659 }
660 }
661
662 #[test]
663 fn test_precision_scale() {
664 let d = Decimal::with_precision_scale("123.456", Some(10), Some(2)).unwrap();
666 assert_eq!(d.to_string(), "123.46");
667
668 let d = Decimal::with_precision_scale("12345.67", Some(5), Some(2)).unwrap();
670 assert_eq!(d.to_string(), "345.67"); let d = Decimal::with_precision_scale("99.999", Some(5), Some(2)).unwrap();
674 assert_eq!(d.to_string(), "100"); }
676
677 #[test]
678 fn test_from_integer() {
679 let d = Decimal::from(42i64);
680 assert_eq!(d.to_string(), "42");
681
682 let d = Decimal::from(-100i32);
683 assert_eq!(d.to_string(), "-100");
684 }
685
686 #[test]
687 fn test_serialization() {
688 let d = Decimal::from_str("123.456").unwrap();
689 let json = serde_json::to_string(&d).unwrap();
690 assert_eq!(json, "\"123.456\"");
691
692 let restored: Decimal = serde_json::from_str(&json).unwrap();
693 assert_eq!(d, restored);
694 }
695
696 #[test]
697 fn test_byte_efficiency() {
698 let d = Decimal::from_str("123456789").unwrap();
700 assert!(
702 d.byte_len() <= 10,
703 "Expected <= 10 bytes, got {}",
704 d.byte_len()
705 );
706
707 let d = Decimal::from_str("0.000001").unwrap();
708 assert!(
710 d.byte_len() <= 6,
711 "Expected <= 6 bytes, got {}",
712 d.byte_len()
713 );
714 }
715
716 #[test]
719 fn test_infinity_creation() {
720 let pos_inf = Decimal::infinity();
721 assert!(pos_inf.is_pos_infinity());
722 assert!(pos_inf.is_infinity());
723 assert!(!pos_inf.is_neg_infinity());
724 assert!(!pos_inf.is_nan());
725 assert!(pos_inf.is_special());
726 assert!(!pos_inf.is_finite());
727 assert_eq!(pos_inf.to_string(), "Infinity");
728
729 let neg_inf = Decimal::neg_infinity();
730 assert!(neg_inf.is_neg_infinity());
731 assert!(neg_inf.is_infinity());
732 assert!(!neg_inf.is_pos_infinity());
733 assert!(!neg_inf.is_nan());
734 assert!(neg_inf.is_special());
735 assert!(!neg_inf.is_finite());
736 assert_eq!(neg_inf.to_string(), "-Infinity");
737 }
738
739 #[test]
740 fn test_nan_creation() {
741 let nan = Decimal::nan();
742 assert!(nan.is_nan());
743 assert!(nan.is_special());
744 assert!(!nan.is_finite());
745 assert!(!nan.is_infinity());
746 assert!(!nan.is_zero());
747 assert_eq!(nan.to_string(), "NaN");
748 }
749
750 #[test]
751 fn test_special_value_from_str() {
752 let pos_inf = Decimal::from_str("Infinity").unwrap();
753 assert!(pos_inf.is_pos_infinity());
754
755 let neg_inf = Decimal::from_str("-Infinity").unwrap();
756 assert!(neg_inf.is_neg_infinity());
757
758 let nan = Decimal::from_str("NaN").unwrap();
759 assert!(nan.is_nan());
760
761 let inf = Decimal::from_str("infinity").unwrap();
763 assert!(inf.is_pos_infinity());
764
765 let inf = Decimal::from_str("INF").unwrap();
766 assert!(inf.is_pos_infinity());
767 }
768
769 #[test]
770 fn test_special_value_ordering() {
771 let neg_inf = Decimal::neg_infinity();
773 let neg_num = Decimal::from_str("-1000").unwrap();
774 let zero = Decimal::from_str("0").unwrap();
775 let pos_num = Decimal::from_str("1000").unwrap();
776 let pos_inf = Decimal::infinity();
777 let nan = Decimal::nan();
778
779 assert!(neg_inf < neg_num);
780 assert!(neg_num < zero);
781 assert!(zero < pos_num);
782 assert!(pos_num < pos_inf);
783 assert!(pos_inf < nan);
784
785 assert!(neg_inf.as_bytes() < neg_num.as_bytes());
787 assert!(neg_num.as_bytes() < zero.as_bytes());
788 assert!(zero.as_bytes() < pos_num.as_bytes());
789 assert!(pos_num.as_bytes() < pos_inf.as_bytes());
790 assert!(pos_inf.as_bytes() < nan.as_bytes());
791 }
792
793 #[test]
794 fn test_special_value_equality() {
795 let nan1 = Decimal::from_str("NaN").unwrap();
797 let nan2 = Decimal::from_str("nan").unwrap();
798 let nan3 = Decimal::nan();
799 assert_eq!(nan1, nan2);
800 assert_eq!(nan2, nan3);
801
802 let inf1 = Decimal::infinity();
804 let inf2 = Decimal::from_str("Infinity").unwrap();
805 assert_eq!(inf1, inf2);
806
807 let neg_inf1 = Decimal::neg_infinity();
808 let neg_inf2 = Decimal::from_str("-Infinity").unwrap();
809 assert_eq!(neg_inf1, neg_inf2);
810 }
811
812 #[test]
813 fn test_special_value_serialization() {
814 let inf = Decimal::infinity();
815 let json = serde_json::to_string(&inf).unwrap();
816 assert_eq!(json, "\"Infinity\"");
817 let restored: Decimal = serde_json::from_str(&json).unwrap();
818 assert_eq!(inf, restored);
819
820 let nan = Decimal::nan();
821 let json = serde_json::to_string(&nan).unwrap();
822 assert_eq!(json, "\"NaN\"");
823 let restored: Decimal = serde_json::from_str(&json).unwrap();
824 assert_eq!(nan, restored);
825 }
826
827 #[test]
828 fn test_special_value_byte_efficiency() {
829 assert_eq!(Decimal::infinity().byte_len(), 3);
831 assert_eq!(Decimal::neg_infinity().byte_len(), 3);
832 assert_eq!(Decimal::nan().byte_len(), 3);
833 }
834
835 #[test]
838 fn test_negative_scale() {
839 let d = Decimal::with_precision_scale("12345", Some(10), Some(-3)).unwrap();
841 assert_eq!(d.to_string(), "12000");
842
843 let d = Decimal::with_precision_scale("12500", Some(10), Some(-3)).unwrap();
845 assert_eq!(d.to_string(), "13000");
846
847 let d = Decimal::with_precision_scale("1234", Some(10), Some(-2)).unwrap();
849 assert_eq!(d.to_string(), "1200");
850 }
851
852 #[test]
853 fn test_negative_scale_with_precision() {
854 let d = Decimal::with_precision_scale("12345", Some(2), Some(-3)).unwrap();
856 assert_eq!(d.to_string(), "12000");
857 }
858
859 #[test]
862 fn test_invalid_format_errors() {
863 let result = Decimal::from_str("1.2.3");
865 assert!(result.is_err());
866 assert!(matches!(
867 result.unwrap_err(),
868 DecimalError::InvalidFormat(_)
869 ));
870
871 let result = Decimal::from_str("12abc");
873 assert!(result.is_err());
874
875 let result = Decimal::from_str("1e");
877 assert!(result.is_err());
878 assert!(matches!(
879 result.unwrap_err(),
880 DecimalError::InvalidFormat(_)
881 ));
882
883 let result = Decimal::from_str("1eabc");
885 assert!(result.is_err());
886
887 let d = Decimal::from_str("").unwrap();
889 assert!(d.is_zero());
890
891 let result = Decimal::from_str("-");
893 assert!(result.is_ok()); }
895
896 #[test]
897 fn test_leading_plus_sign() {
898 let d = Decimal::from_str("+123.456").unwrap();
899 assert_eq!(d.to_string(), "123.456");
900 assert!(d.is_positive());
901 }
902
903 #[test]
904 fn test_scientific_notation() {
905 let d = Decimal::from_str("1.5e10").unwrap();
906 assert_eq!(d.to_string(), "15000000000");
907
908 let d = Decimal::from_str("1.5E-3").unwrap();
909 assert_eq!(d.to_string(), "0.0015");
910
911 let d = Decimal::from_str("1e+5").unwrap();
912 assert_eq!(d.to_string(), "100000");
913 }
914
915 #[test]
916 fn test_leading_decimal_point() {
917 let d = Decimal::from_str(".5").unwrap();
919 assert_eq!(d.to_string(), "0.5");
920
921 let d = Decimal::from_str("-.25").unwrap();
922 assert_eq!(d.to_string(), "-0.25");
923 }
924
925 #[test]
926 fn test_trailing_zeros() {
927 let d = Decimal::from_str("100").unwrap();
928 assert_eq!(d.to_string(), "100");
929
930 let d = Decimal::from_str("1.500").unwrap();
931 assert_eq!(d.to_string(), "1.5");
932 }
933
934 #[test]
935 fn test_leading_zeros() {
936 let d = Decimal::from_str("007").unwrap();
937 assert_eq!(d.to_string(), "7");
938
939 let d = Decimal::from_str("00.123").unwrap();
940 assert_eq!(d.to_string(), "0.123");
941 }
942
943 #[test]
946 fn test_into_bytes() {
947 let d = Decimal::from_str("123.456").unwrap();
948 let bytes_ref = d.as_bytes().to_vec();
949 let bytes_owned = d.into_bytes();
950 assert_eq!(bytes_ref, bytes_owned);
951 }
952
953 #[test]
954 fn test_clone() {
955 let d1 = Decimal::from_str("123.456").unwrap();
956 let d2 = d1.clone();
957 assert_eq!(d1, d2);
958 assert_eq!(d1.as_bytes(), d2.as_bytes());
959 }
960
961 #[test]
962 fn test_hash() {
963 use std::collections::HashSet;
964
965 let mut set = HashSet::new();
966 set.insert(Decimal::from_str("123.456").unwrap());
967 set.insert(Decimal::from_str("123.456").unwrap()); set.insert(Decimal::from_str("789.012").unwrap());
969
970 assert_eq!(set.len(), 2);
971 assert!(set.contains(&Decimal::from_str("123.456").unwrap()));
972 }
973
974 #[test]
975 fn test_debug_format() {
976 let d = Decimal::from_str("123.456").unwrap();
977 let debug_str = format!("{:?}", d);
978 assert!(debug_str.contains("Decimal"));
979 assert!(debug_str.contains("123.456"));
980 }
981
982 #[test]
983 fn test_ord_trait() {
984 use std::cmp::Ordering;
985
986 let a = Decimal::from_str("1").unwrap();
987 let b = Decimal::from_str("2").unwrap();
988 let c = Decimal::from_str("1").unwrap();
989
990 assert_eq!(a.cmp(&b), Ordering::Less);
991 assert_eq!(b.cmp(&a), Ordering::Greater);
992 assert_eq!(a.cmp(&c), Ordering::Equal);
993 }
994
995 #[test]
996 fn test_from_bytes_invalid() {
997 let result = Decimal::from_bytes(&[]);
999 assert!(result.is_err());
1000
1001 let result = Decimal::from_bytes(&[0x00]);
1003 assert!(result.is_err());
1004 }
1005
1006 #[test]
1007 fn test_deserialize_from_string_number() {
1008 let d: Decimal = serde_json::from_str("\"42\"").unwrap();
1010 assert_eq!(d.to_string(), "42");
1011
1012 let d: Decimal = serde_json::from_str("\"-100\"").unwrap();
1013 assert_eq!(d.to_string(), "-100");
1014
1015 let d: Decimal = serde_json::from_str("\"1.5e10\"").unwrap();
1016 assert_eq!(d.to_string(), "15000000000");
1017 }
1018
1019 #[test]
1020 fn test_from_various_integer_types() {
1021 assert_eq!(Decimal::from(0i32).to_string(), "0");
1022 assert_eq!(Decimal::from(i32::MAX).to_string(), "2147483647");
1023 assert_eq!(Decimal::from(i32::MIN).to_string(), "-2147483648");
1024 assert_eq!(Decimal::from(i64::MAX).to_string(), "9223372036854775807");
1025 assert_eq!(Decimal::from(i64::MIN).to_string(), "-9223372036854775808");
1026 }
1027
1028 #[test]
1029 fn test_precision_overflow() {
1030 let result = Decimal::from_str("1e20000");
1032 assert!(result.is_err());
1033 assert!(matches!(
1034 result.unwrap_err(),
1035 DecimalError::PrecisionOverflow
1036 ));
1037
1038 let result = Decimal::from_str("1e-20000");
1040 assert!(result.is_err());
1041 assert!(matches!(
1042 result.unwrap_err(),
1043 DecimalError::PrecisionOverflow
1044 ));
1045 }
1046
1047 #[test]
1048 fn test_all_zeros_variations() {
1049 let d = Decimal::from_str("0").unwrap();
1050 assert!(d.is_zero());
1051
1052 let d = Decimal::from_str("0.0").unwrap();
1053 assert!(d.is_zero());
1054
1055 let d = Decimal::from_str("00.00").unwrap();
1056 assert!(d.is_zero());
1057
1058 let d = Decimal::from_str("-0").unwrap();
1059 assert!(d.is_zero());
1060 }
1062
1063 #[test]
1066 fn test_rounding_all_nines() {
1067 let d = Decimal::with_precision_scale("99.999", Some(10), Some(2)).unwrap();
1069 assert_eq!(d.to_string(), "100");
1070
1071 let d = Decimal::with_precision_scale("9.99", Some(10), Some(1)).unwrap();
1073 assert_eq!(d.to_string(), "10");
1074
1075 let d = Decimal::with_precision_scale("999", Some(10), Some(-1)).unwrap();
1077 assert_eq!(d.to_string(), "1000");
1078 }
1079
1080 #[test]
1081 fn test_negative_scale_small_number() {
1082 let d = Decimal::with_precision_scale("4", Some(10), Some(-1)).unwrap();
1084 assert_eq!(d.to_string(), "0");
1085
1086 let d = Decimal::with_precision_scale("5", Some(10), Some(-1)).unwrap();
1088 assert_eq!(d.to_string(), "10");
1089
1090 let d = Decimal::with_precision_scale("-4", Some(10), Some(-1)).unwrap();
1092 assert_eq!(d.to_string(), "0");
1093
1094 let d = Decimal::with_precision_scale("-5", Some(10), Some(-1)).unwrap();
1096 assert_eq!(d.to_string(), "-10");
1097 }
1098
1099 #[test]
1100 fn test_precision_truncation() {
1101 let d = Decimal::with_precision_scale("123456", Some(3), Some(0)).unwrap();
1103 assert_eq!(d.to_string(), "456");
1104
1105 let d = Decimal::with_precision_scale("12345.67", Some(4), Some(2)).unwrap();
1107 assert_eq!(d.to_string(), "45.67");
1108 }
1109
1110 #[test]
1111 fn test_very_small_numbers() {
1112 let d = Decimal::from_str("0.000000001").unwrap();
1113 assert_eq!(d.to_string(), "0.000000001");
1114 assert!(d.is_positive());
1115
1116 let d = Decimal::from_str("-0.000000001").unwrap();
1117 assert_eq!(d.to_string(), "-0.000000001");
1118 assert!(d.is_negative());
1119 }
1120
1121 #[test]
1122 fn test_very_large_numbers() {
1123 let d = Decimal::from_str("999999999999999999999999999999").unwrap();
1124 assert_eq!(d.to_string(), "999999999999999999999999999999");
1125
1126 let d = Decimal::from_str("-999999999999999999999999999999").unwrap();
1127 assert_eq!(d.to_string(), "-999999999999999999999999999999");
1128 }
1129
1130 #[test]
1131 fn test_max_exponent_boundary() {
1132 let d = Decimal::from_str("1e16000").unwrap();
1134 assert!(d.is_positive());
1135
1136 let result = Decimal::from_str("1e17000");
1138 assert!(result.is_err());
1139 }
1140
1141 #[test]
1142 fn test_min_exponent_boundary() {
1143 let d = Decimal::from_str("1e-16000").unwrap();
1145 assert!(d.is_positive());
1146
1147 let result = Decimal::from_str("1e-17000");
1149 assert!(result.is_err());
1150 }
1151
1152 #[test]
1153 fn test_odd_digit_count() {
1154 let d = Decimal::from_str("12345").unwrap();
1156 assert_eq!(d.to_string(), "12345");
1157
1158 let d = Decimal::from_str("1").unwrap();
1159 assert_eq!(d.to_string(), "1");
1160
1161 let d = Decimal::from_str("123").unwrap();
1162 assert_eq!(d.to_string(), "123");
1163 }
1164
1165 #[test]
1166 fn test_negative_number_ordering() {
1167 let a = Decimal::from_str("-100").unwrap();
1169 let b = Decimal::from_str("-10").unwrap();
1170 let c = Decimal::from_str("-1").unwrap();
1171
1172 assert!(a < b);
1174 assert!(b < c);
1175
1176 assert!(a.as_bytes() < b.as_bytes());
1178 assert!(b.as_bytes() < c.as_bytes());
1179 }
1180
1181 #[test]
1182 fn test_from_bytes_unchecked_roundtrip() {
1183 let original = Decimal::from_str("123.456").unwrap();
1184 let bytes = original.as_bytes().to_vec();
1185 let restored = Decimal::from_bytes_unchecked(bytes);
1186 assert_eq!(original, restored);
1187 }
1188
1189 #[test]
1190 fn test_special_value_checks() {
1191 let d = Decimal::from_str("123.456").unwrap();
1192 assert!(!d.is_nan());
1193 assert!(!d.is_infinity());
1194 assert!(!d.is_pos_infinity());
1195 assert!(!d.is_neg_infinity());
1196 assert!(!d.is_special());
1197 assert!(d.is_finite());
1198 }
1199
1200 #[test]
1201 fn test_equality_and_hash_consistency() {
1202 use std::collections::HashMap;
1203
1204 let d1 = Decimal::from_str("123.456").unwrap();
1205 let d2 = Decimal::from_str("123.456").unwrap();
1206 let d3 = Decimal::from_str("123.457").unwrap();
1207
1208 assert_eq!(d1, d2);
1210 assert_ne!(d1, d3);
1211
1212 let mut map = HashMap::new();
1214 map.insert(d1.clone(), "first");
1215 map.insert(d2.clone(), "second"); assert_eq!(map.len(), 1);
1217 assert_eq!(map.get(&d1), Some(&"second"));
1218 }
1219
1220 #[test]
1221 fn test_scale_zero() {
1222 let d = Decimal::with_precision_scale("123.999", Some(10), Some(0)).unwrap();
1224 assert_eq!(d.to_string(), "124"); }
1226
1227 #[test]
1228 fn test_only_fractional_with_precision_scale() {
1229 let d = Decimal::with_precision_scale(".5", Some(10), Some(2)).unwrap();
1230 assert_eq!(d.to_string(), "0.5");
1231 }
1232
1233 #[test]
1234 fn test_default_impl() {
1235 let d = Decimal::default();
1236 assert!(d.is_zero());
1237 assert_eq!(d.to_string(), "0");
1238 }
1239
1240 #[test]
1241 fn test_precision_zero_integer_digits() {
1242 let d = Decimal::with_precision_scale("123.456", Some(2), Some(2)).unwrap();
1245 assert_eq!(d.to_string(), "0.46");
1246 }
1247
1248 #[test]
1249 fn test_negative_with_precision_truncation() {
1250 let d = Decimal::with_precision_scale("-123.456", Some(3), Some(2)).unwrap();
1252 assert_eq!(d.to_string(), "-3.46");
1253 }
1254
1255 #[test]
1256 fn test_invalid_sign_byte() {
1257 let result = Decimal::from_bytes(&[0x01, 0x40, 0x00, 0x12]);
1262 assert!(result.is_err());
1263
1264 let result = Decimal::from_bytes(&[0x7F, 0x40, 0x00, 0x12]);
1266 assert!(result.is_err());
1267
1268 let result = Decimal::from_bytes(&[0xFE, 0x40, 0x00, 0x12]);
1270 assert!(result.is_err());
1271 }
1272
1273 #[test]
1274 fn test_invalid_bcd_encoding() {
1275 let invalid_bytes = vec![
1279 0xFF, 0x80, 0x00, 0xAB, ];
1283 let result = Decimal::from_bytes(&invalid_bytes);
1284 assert!(result.is_err());
1285
1286 let invalid_bytes = vec![
1288 0xFF, 0x80, 0x00, 0xA1, ];
1292 let result = Decimal::from_bytes(&invalid_bytes);
1293 assert!(result.is_err());
1294
1295 let invalid_bytes = vec![
1297 0xFF, 0x80, 0x00, 0x1B, ];
1301 let result = Decimal::from_bytes(&invalid_bytes);
1302 assert!(result.is_err());
1303 }
1304
1305 #[test]
1306 fn test_reserved_exponent_positive() {
1307 let bytes_with_reserved_exp = vec![
1314 0xFF, 0xFF, 0xFF, 0x12, ];
1318 let result = Decimal::from_bytes(&bytes_with_reserved_exp);
1319 assert!(result.is_err());
1320
1321 let bytes_with_reserved_exp = vec![
1323 0xFF, 0xFF, 0xFE, 0x12, ];
1327 let result = Decimal::from_bytes(&bytes_with_reserved_exp);
1328 assert!(result.is_err());
1329 }
1330
1331 #[test]
1332 fn test_reserved_exponent_negative() {
1333 let bytes_with_reserved_exp = vec![
1338 0x00, 0x00, 0x00, 0x12, ];
1342 let result = Decimal::from_bytes(&bytes_with_reserved_exp);
1343 assert!(result.is_err());
1344 }
1345
1346 #[test]
1347 fn test_empty_mantissa_bytes() {
1348 let bytes_no_mantissa = vec![
1351 0xFF, 0x80, 0x00, ];
1355 let d = Decimal::from_bytes(&bytes_no_mantissa).unwrap();
1356 assert_eq!(d.to_string(), "0");
1357 }
1358
1359 #[cfg(feature = "rust_decimal")]
1362 mod rust_decimal_tests {
1363 use super::*;
1364
1365 #[test]
1366 fn test_from_rust_decimal() {
1367 use rust_decimal::Decimal as RustDecimal;
1368
1369 let rd = RustDecimal::new(12345, 2); let d: Decimal = rd.try_into().unwrap();
1371 assert_eq!(d.to_string(), "123.45");
1372 }
1373
1374 #[test]
1375 fn test_to_rust_decimal() {
1376 use rust_decimal::Decimal as RustDecimal;
1377
1378 let d = Decimal::from_str("123.45").unwrap();
1379 let rd: RustDecimal = (&d).try_into().unwrap();
1380 assert_eq!(rd.to_string(), "123.45");
1381 }
1382
1383 #[test]
1384 fn test_rust_decimal_roundtrip() {
1385 use rust_decimal::Decimal as RustDecimal;
1386
1387 let values = vec!["0", "1", "-1", "123.456", "-999.999", "0.001"];
1388
1389 for s in values {
1390 let d = Decimal::from_str(s).unwrap();
1391 let rd: RustDecimal = (&d).try_into().unwrap();
1392 let d2: Decimal = rd.try_into().unwrap();
1393 assert_eq!(d, d2, "Roundtrip failed for {}", s);
1394 }
1395 }
1396
1397 #[test]
1398 fn test_rust_decimal_arithmetic() {
1399 use rust_decimal::Decimal as RustDecimal;
1400
1401 let a = Decimal::from_str("100.50").unwrap();
1403 let b = Decimal::from_str("25.25").unwrap();
1404
1405 let ra: RustDecimal = (&a).try_into().unwrap();
1407 let rb: RustDecimal = (&b).try_into().unwrap();
1408 let sum = ra + rb;
1409
1410 let result: Decimal = sum.try_into().unwrap();
1412 assert_eq!(result.to_string(), "125.75");
1413 }
1414
1415 #[test]
1416 fn test_rust_decimal_from_owned() {
1417 use rust_decimal::Decimal as RustDecimal;
1418
1419 let d = Decimal::from_str("456.789").unwrap();
1421 let rd: RustDecimal = d.try_into().unwrap();
1422 assert_eq!(rd.to_string(), "456.789");
1423 }
1424
1425 #[test]
1426 fn test_rust_decimal_special_values_fail() {
1427 use rust_decimal::Decimal as RustDecimal;
1428
1429 let inf = Decimal::infinity();
1431 let result: Result<RustDecimal, _> = (&inf).try_into();
1432 assert!(result.is_err());
1433
1434 let nan = Decimal::nan();
1436 let result: Result<RustDecimal, _> = (&nan).try_into();
1437 assert!(result.is_err());
1438 }
1439 }
1440
1441 #[cfg(feature = "bigdecimal")]
1444 mod bigdecimal_tests {
1445 use super::*;
1446
1447 #[test]
1448 fn test_from_bigdecimal() {
1449 use bigdecimal::BigDecimal;
1450 use std::str::FromStr;
1451
1452 let bd = BigDecimal::from_str("123.45").unwrap();
1453 let d: Decimal = bd.try_into().unwrap();
1454 assert_eq!(d.to_string(), "123.45");
1455 }
1456
1457 #[test]
1458 fn test_to_bigdecimal() {
1459 use bigdecimal::BigDecimal;
1460
1461 let d = Decimal::from_str("123.45").unwrap();
1462 let bd: BigDecimal = (&d).try_into().unwrap();
1463 assert_eq!(bd.to_string(), "123.45");
1464 }
1465
1466 #[test]
1467 fn test_bigdecimal_roundtrip() {
1468 use bigdecimal::BigDecimal;
1469
1470 let values = vec!["0", "1", "-1", "123.456", "-999.999", "0.001"];
1471
1472 for s in values {
1473 let d = Decimal::from_str(s).unwrap();
1474 let bd: BigDecimal = (&d).try_into().unwrap();
1475 let d2: Decimal = bd.try_into().unwrap();
1476 assert_eq!(d, d2, "Roundtrip failed for {}", s);
1477 }
1478 }
1479
1480 #[test]
1481 fn test_bigdecimal_from_owned() {
1482 use bigdecimal::BigDecimal;
1483
1484 let d = Decimal::from_str("456.789").unwrap();
1486 let bd: BigDecimal = d.try_into().unwrap();
1487 assert_eq!(bd.to_string(), "456.789");
1488 }
1489
1490 #[test]
1491 fn test_bigdecimal_from_ref() {
1492 use bigdecimal::BigDecimal;
1493 use std::str::FromStr;
1494
1495 let bd = BigDecimal::from_str("789.012").unwrap();
1497 let d: Decimal = (&bd).try_into().unwrap();
1498 assert_eq!(d.to_string(), "789.012");
1499 }
1500
1501 #[test]
1502 fn test_bigdecimal_special_values_fail() {
1503 use bigdecimal::BigDecimal;
1504
1505 let inf = Decimal::infinity();
1507 let result: Result<BigDecimal, _> = (&inf).try_into();
1508 assert!(result.is_err());
1509
1510 let nan = Decimal::nan();
1512 let result: Result<BigDecimal, _> = (&nan).try_into();
1513 assert!(result.is_err());
1514 }
1515 }
1516}