1mod encoding;
79
80use std::cmp::Ordering;
81use std::fmt;
82use std::hash::{Hash, Hasher};
83use std::str::FromStr;
84
85use serde::{Deserialize, Deserializer, Serialize, Serializer};
86
87pub use encoding::DecimalError;
88pub use encoding::SpecialValue;
89use encoding::{
90 decode_special_value, decode_to_string, encode_decimal, encode_decimal_with_constraints,
91 encode_special_value, ENCODING_NAN, ENCODING_NEG_INFINITY, ENCODING_POS_INFINITY,
92};
93
94#[derive(Clone)]
107pub struct Decimal {
108 bytes: Vec<u8>,
109}
110
111impl Decimal {
112 pub fn with_precision_scale(
140 s: &str,
141 precision: Option<u32>,
142 scale: Option<i32>,
143 ) -> Result<Self, DecimalError> {
144 let bytes = encode_decimal_with_constraints(s, precision, scale)?;
145 Ok(Self { bytes })
146 }
147
148 pub fn from_bytes(bytes: &[u8]) -> Result<Self, DecimalError> {
165 let _ = decode_to_string(bytes)?;
167 Ok(Self {
168 bytes: bytes.to_vec(),
169 })
170 }
171
172 #[inline]
179 pub fn from_bytes_unchecked(bytes: Vec<u8>) -> Self {
180 Self { bytes }
181 }
182
183 #[inline]
188 pub fn as_bytes(&self) -> &[u8] {
189 &self.bytes
190 }
191
192 #[inline]
194 pub fn into_bytes(self) -> Vec<u8> {
195 self.bytes
196 }
197
198 pub fn is_zero(&self) -> bool {
200 self.bytes.len() == 1 && self.bytes[0] == encoding::SIGN_ZERO
201 }
202
203 pub fn is_negative(&self) -> bool {
205 !self.bytes.is_empty() && self.bytes[0] == encoding::SIGN_NEGATIVE
206 }
207
208 pub fn is_positive(&self) -> bool {
210 !self.bytes.is_empty() && self.bytes[0] == encoding::SIGN_POSITIVE
211 }
212
213 pub fn is_pos_infinity(&self) -> bool {
215 self.bytes.as_slice() == ENCODING_POS_INFINITY
216 }
217
218 pub fn is_neg_infinity(&self) -> bool {
220 self.bytes.as_slice() == ENCODING_NEG_INFINITY
221 }
222
223 pub fn is_infinity(&self) -> bool {
225 self.is_pos_infinity() || self.is_neg_infinity()
226 }
227
228 pub fn is_nan(&self) -> bool {
230 self.bytes.as_slice() == ENCODING_NAN
231 }
232
233 pub fn is_special(&self) -> bool {
235 decode_special_value(&self.bytes).is_some()
236 }
237
238 pub fn is_finite(&self) -> bool {
240 !self.is_special()
241 }
242
243 #[inline]
245 pub fn byte_len(&self) -> usize {
246 self.bytes.len()
247 }
248
249 pub fn infinity() -> Self {
266 Self {
267 bytes: encode_special_value(SpecialValue::Infinity),
268 }
269 }
270
271 pub fn neg_infinity() -> Self {
288 Self {
289 bytes: encode_special_value(SpecialValue::NegInfinity),
290 }
291 }
292
293 pub fn nan() -> Self {
322 Self {
323 bytes: encode_special_value(SpecialValue::NaN),
324 }
325 }
326}
327
328impl FromStr for Decimal {
329 type Err = DecimalError;
330
331 fn from_str(s: &str) -> Result<Self, Self::Err> {
346 let bytes = encode_decimal(s)?;
347 Ok(Self { bytes })
348 }
349}
350
351impl fmt::Display for Decimal {
352 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
353 let s = decode_to_string(&self.bytes).expect("Decimal contains valid bytes");
354 write!(f, "{}", s)
355 }
356}
357
358impl fmt::Debug for Decimal {
359 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
360 let value = decode_to_string(&self.bytes).expect("Decimal contains valid bytes");
361 f.debug_struct("Decimal")
362 .field("value", &value)
363 .field("bytes", &self.bytes)
364 .finish()
365 }
366}
367
368impl PartialEq for Decimal {
369 fn eq(&self, other: &Self) -> bool {
370 self.bytes == other.bytes
371 }
372}
373
374impl Eq for Decimal {}
375
376impl PartialOrd for Decimal {
377 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
378 Some(self.cmp(other))
379 }
380}
381
382impl Ord for Decimal {
383 fn cmp(&self, other: &Self) -> Ordering {
384 self.bytes.cmp(&other.bytes)
386 }
387}
388
389impl Hash for Decimal {
390 fn hash<H: Hasher>(&self, state: &mut H) {
391 self.bytes.hash(state);
392 }
393}
394
395impl Serialize for Decimal {
396 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
397 where
398 S: Serializer,
399 {
400 serializer.serialize_str(&self.to_string())
402 }
403}
404
405impl<'de> Deserialize<'de> for Decimal {
406 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
407 where
408 D: Deserializer<'de>,
409 {
410 let s = String::deserialize(deserializer)?;
411 Decimal::from_str(&s).map_err(serde::de::Error::custom)
412 }
413}
414
415macro_rules! impl_from_int {
417 ($($t:ty),*) => {
418 $(
419 impl From<$t> for Decimal {
420 fn from(val: $t) -> Self {
421 Decimal::from_str(&val.to_string()).expect("Integer is always valid")
422 }
423 }
424 )*
425 };
426}
427
428impl_from_int!(i8, i16, i32, i64, i128, u8, u16, u32, u64, u128);
429
430impl Default for Decimal {
431 fn default() -> Self {
432 Decimal {
433 bytes: vec![encoding::SIGN_ZERO],
434 }
435 }
436}
437
438#[cfg(feature = "rust_decimal")]
443mod rust_decimal_interop {
444 use super::{Decimal, DecimalError};
445 use std::str::FromStr;
446
447 impl TryFrom<rust_decimal::Decimal> for Decimal {
448 type Error = DecimalError;
449
450 fn try_from(value: rust_decimal::Decimal) -> Result<Self, Self::Error> {
463 Decimal::from_str(&value.to_string())
464 }
465 }
466
467 impl TryFrom<&Decimal> for rust_decimal::Decimal {
468 type Error = rust_decimal::Error;
469
470 fn try_from(value: &Decimal) -> Result<Self, Self::Error> {
486 use std::str::FromStr;
487 rust_decimal::Decimal::from_str(&value.to_string())
488 }
489 }
490
491 impl TryFrom<Decimal> for rust_decimal::Decimal {
492 type Error = rust_decimal::Error;
493
494 fn try_from(value: Decimal) -> Result<Self, Self::Error> {
495 rust_decimal::Decimal::try_from(&value)
496 }
497 }
498}
499
500#[cfg(feature = "bigdecimal")]
508mod bigdecimal_interop {
509 use super::{Decimal, DecimalError};
510 use std::str::FromStr;
511
512 impl TryFrom<bigdecimal::BigDecimal> for Decimal {
513 type Error = DecimalError;
514
515 fn try_from(value: bigdecimal::BigDecimal) -> Result<Self, Self::Error> {
517 Decimal::from_str(&value.to_string())
518 }
519 }
520
521 impl TryFrom<&bigdecimal::BigDecimal> for Decimal {
522 type Error = DecimalError;
523
524 fn try_from(value: &bigdecimal::BigDecimal) -> Result<Self, Self::Error> {
525 Decimal::from_str(&value.to_string())
526 }
527 }
528
529 impl TryFrom<&Decimal> for bigdecimal::BigDecimal {
530 type Error = bigdecimal::ParseBigDecimalError;
531
532 fn try_from(value: &Decimal) -> Result<Self, Self::Error> {
537 use std::str::FromStr;
538 bigdecimal::BigDecimal::from_str(&value.to_string())
539 }
540 }
541
542 impl TryFrom<Decimal> for bigdecimal::BigDecimal {
543 type Error = bigdecimal::ParseBigDecimalError;
544
545 fn try_from(value: Decimal) -> Result<Self, Self::Error> {
546 bigdecimal::BigDecimal::try_from(&value)
547 }
548 }
549}
550
551#[cfg(test)]
555mod tests {
556 use super::*;
557
558 #[test]
559 fn test_from_str() {
560 let d = Decimal::from_str("123.456").unwrap();
561 assert_eq!(d.to_string(), "123.456");
562 }
563
564 #[test]
565 fn test_zero() {
566 let d = Decimal::from_str("0").unwrap();
567 assert!(d.is_zero());
568 assert!(!d.is_negative());
569 assert!(!d.is_positive());
570 assert!(d.is_finite());
571 assert!(!d.is_special());
572 }
573
574 #[test]
575 fn test_negative() {
576 let d = Decimal::from_str("-123.456").unwrap();
577 assert!(d.is_negative());
578 assert!(!d.is_zero());
579 assert!(!d.is_positive());
580 assert!(d.is_finite());
581 }
582
583 #[test]
584 fn test_positive() {
585 let d = Decimal::from_str("123.456").unwrap();
586 assert!(d.is_positive());
587 assert!(!d.is_zero());
588 assert!(!d.is_negative());
589 assert!(d.is_finite());
590 }
591
592 #[test]
593 fn test_ordering() {
594 let values = vec!["-100", "-10", "-1", "-0.1", "0", "0.1", "1", "10", "100"];
595 let decimals: Vec<Decimal> = values
596 .iter()
597 .map(|s| Decimal::from_str(s).unwrap())
598 .collect();
599
600 for i in 0..decimals.len() - 1 {
602 assert!(
603 decimals[i] < decimals[i + 1],
604 "{} should be < {}",
605 values[i],
606 values[i + 1]
607 );
608 }
609
610 for i in 0..decimals.len() - 1 {
612 assert!(
613 decimals[i].as_bytes() < decimals[i + 1].as_bytes(),
614 "bytes of {} should be < bytes of {}",
615 values[i],
616 values[i + 1]
617 );
618 }
619 }
620
621 #[test]
622 fn test_roundtrip() {
623 let values = vec![
624 "0", "1", "-1", "123.456", "-123.456", "0.001", "0.1", "10", "100", "1000000",
625 "-1000000",
626 ];
627
628 for s in values {
629 let d = Decimal::from_str(s).unwrap();
630 let bytes = d.as_bytes();
631 let restored = Decimal::from_bytes(bytes).unwrap();
632 assert_eq!(d, restored, "Roundtrip failed for {}", s);
633 }
634 }
635
636 #[test]
637 fn test_precision_scale() {
638 let d = Decimal::with_precision_scale("123.456", Some(10), Some(2)).unwrap();
640 assert_eq!(d.to_string(), "123.46");
641
642 let d = Decimal::with_precision_scale("12345.67", Some(5), Some(2)).unwrap();
644 assert_eq!(d.to_string(), "345.67"); let d = Decimal::with_precision_scale("99.999", Some(5), Some(2)).unwrap();
648 assert_eq!(d.to_string(), "100"); }
650
651 #[test]
652 fn test_from_integer() {
653 let d = Decimal::from(42i64);
654 assert_eq!(d.to_string(), "42");
655
656 let d = Decimal::from(-100i32);
657 assert_eq!(d.to_string(), "-100");
658 }
659
660 #[test]
661 fn test_serialization() {
662 let d = Decimal::from_str("123.456").unwrap();
663 let json = serde_json::to_string(&d).unwrap();
664 assert_eq!(json, "\"123.456\"");
665
666 let restored: Decimal = serde_json::from_str(&json).unwrap();
667 assert_eq!(d, restored);
668 }
669
670 #[test]
671 fn test_byte_efficiency() {
672 let d = Decimal::from_str("123456789").unwrap();
674 assert!(
676 d.byte_len() <= 10,
677 "Expected <= 10 bytes, got {}",
678 d.byte_len()
679 );
680
681 let d = Decimal::from_str("0.000001").unwrap();
682 assert!(
684 d.byte_len() <= 6,
685 "Expected <= 6 bytes, got {}",
686 d.byte_len()
687 );
688 }
689
690 #[test]
693 fn test_infinity_creation() {
694 let pos_inf = Decimal::infinity();
695 assert!(pos_inf.is_pos_infinity());
696 assert!(pos_inf.is_infinity());
697 assert!(!pos_inf.is_neg_infinity());
698 assert!(!pos_inf.is_nan());
699 assert!(pos_inf.is_special());
700 assert!(!pos_inf.is_finite());
701 assert_eq!(pos_inf.to_string(), "Infinity");
702
703 let neg_inf = Decimal::neg_infinity();
704 assert!(neg_inf.is_neg_infinity());
705 assert!(neg_inf.is_infinity());
706 assert!(!neg_inf.is_pos_infinity());
707 assert!(!neg_inf.is_nan());
708 assert!(neg_inf.is_special());
709 assert!(!neg_inf.is_finite());
710 assert_eq!(neg_inf.to_string(), "-Infinity");
711 }
712
713 #[test]
714 fn test_nan_creation() {
715 let nan = Decimal::nan();
716 assert!(nan.is_nan());
717 assert!(nan.is_special());
718 assert!(!nan.is_finite());
719 assert!(!nan.is_infinity());
720 assert!(!nan.is_zero());
721 assert_eq!(nan.to_string(), "NaN");
722 }
723
724 #[test]
725 fn test_special_value_from_str() {
726 let pos_inf = Decimal::from_str("Infinity").unwrap();
727 assert!(pos_inf.is_pos_infinity());
728
729 let neg_inf = Decimal::from_str("-Infinity").unwrap();
730 assert!(neg_inf.is_neg_infinity());
731
732 let nan = Decimal::from_str("NaN").unwrap();
733 assert!(nan.is_nan());
734
735 let inf = Decimal::from_str("infinity").unwrap();
737 assert!(inf.is_pos_infinity());
738
739 let inf = Decimal::from_str("INF").unwrap();
740 assert!(inf.is_pos_infinity());
741 }
742
743 #[test]
744 fn test_special_value_ordering() {
745 let neg_inf = Decimal::neg_infinity();
747 let neg_num = Decimal::from_str("-1000").unwrap();
748 let zero = Decimal::from_str("0").unwrap();
749 let pos_num = Decimal::from_str("1000").unwrap();
750 let pos_inf = Decimal::infinity();
751 let nan = Decimal::nan();
752
753 assert!(neg_inf < neg_num);
754 assert!(neg_num < zero);
755 assert!(zero < pos_num);
756 assert!(pos_num < pos_inf);
757 assert!(pos_inf < nan);
758
759 assert!(neg_inf.as_bytes() < neg_num.as_bytes());
761 assert!(neg_num.as_bytes() < zero.as_bytes());
762 assert!(zero.as_bytes() < pos_num.as_bytes());
763 assert!(pos_num.as_bytes() < pos_inf.as_bytes());
764 assert!(pos_inf.as_bytes() < nan.as_bytes());
765 }
766
767 #[test]
768 fn test_special_value_equality() {
769 let nan1 = Decimal::from_str("NaN").unwrap();
771 let nan2 = Decimal::from_str("nan").unwrap();
772 let nan3 = Decimal::nan();
773 assert_eq!(nan1, nan2);
774 assert_eq!(nan2, nan3);
775
776 let inf1 = Decimal::infinity();
778 let inf2 = Decimal::from_str("Infinity").unwrap();
779 assert_eq!(inf1, inf2);
780
781 let neg_inf1 = Decimal::neg_infinity();
782 let neg_inf2 = Decimal::from_str("-Infinity").unwrap();
783 assert_eq!(neg_inf1, neg_inf2);
784 }
785
786 #[test]
787 fn test_special_value_serialization() {
788 let inf = Decimal::infinity();
789 let json = serde_json::to_string(&inf).unwrap();
790 assert_eq!(json, "\"Infinity\"");
791 let restored: Decimal = serde_json::from_str(&json).unwrap();
792 assert_eq!(inf, restored);
793
794 let nan = Decimal::nan();
795 let json = serde_json::to_string(&nan).unwrap();
796 assert_eq!(json, "\"NaN\"");
797 let restored: Decimal = serde_json::from_str(&json).unwrap();
798 assert_eq!(nan, restored);
799 }
800
801 #[test]
802 fn test_special_value_byte_efficiency() {
803 assert_eq!(Decimal::infinity().byte_len(), 3);
805 assert_eq!(Decimal::neg_infinity().byte_len(), 3);
806 assert_eq!(Decimal::nan().byte_len(), 3);
807 }
808
809 #[test]
812 fn test_negative_scale() {
813 let d = Decimal::with_precision_scale("12345", Some(10), Some(-3)).unwrap();
815 assert_eq!(d.to_string(), "12000");
816
817 let d = Decimal::with_precision_scale("12500", Some(10), Some(-3)).unwrap();
819 assert_eq!(d.to_string(), "13000");
820
821 let d = Decimal::with_precision_scale("1234", Some(10), Some(-2)).unwrap();
823 assert_eq!(d.to_string(), "1200");
824 }
825
826 #[test]
827 fn test_negative_scale_with_precision() {
828 let d = Decimal::with_precision_scale("12345", Some(2), Some(-3)).unwrap();
830 assert_eq!(d.to_string(), "12000");
831 }
832
833 #[test]
836 fn test_invalid_format_errors() {
837 let result = Decimal::from_str("1.2.3");
839 assert!(result.is_err());
840 assert!(matches!(
841 result.unwrap_err(),
842 DecimalError::InvalidFormat(_)
843 ));
844
845 let result = Decimal::from_str("12abc");
847 assert!(result.is_err());
848
849 let result = Decimal::from_str("1e");
851 assert!(result.is_err());
852 assert!(matches!(
853 result.unwrap_err(),
854 DecimalError::InvalidFormat(_)
855 ));
856
857 let result = Decimal::from_str("1eabc");
859 assert!(result.is_err());
860
861 let d = Decimal::from_str("").unwrap();
863 assert!(d.is_zero());
864
865 let result = Decimal::from_str("-");
867 assert!(result.is_ok()); }
869
870 #[test]
871 fn test_leading_plus_sign() {
872 let d = Decimal::from_str("+123.456").unwrap();
873 assert_eq!(d.to_string(), "123.456");
874 assert!(d.is_positive());
875 }
876
877 #[test]
878 fn test_scientific_notation() {
879 let d = Decimal::from_str("1.5e10").unwrap();
880 assert_eq!(d.to_string(), "15000000000");
881
882 let d = Decimal::from_str("1.5E-3").unwrap();
883 assert_eq!(d.to_string(), "0.0015");
884
885 let d = Decimal::from_str("1e+5").unwrap();
886 assert_eq!(d.to_string(), "100000");
887 }
888
889 #[test]
890 fn test_leading_decimal_point() {
891 let d = Decimal::from_str(".5").unwrap();
893 assert_eq!(d.to_string(), "0.5");
894
895 let d = Decimal::from_str("-.25").unwrap();
896 assert_eq!(d.to_string(), "-0.25");
897 }
898
899 #[test]
900 fn test_trailing_zeros() {
901 let d = Decimal::from_str("100").unwrap();
902 assert_eq!(d.to_string(), "100");
903
904 let d = Decimal::from_str("1.500").unwrap();
905 assert_eq!(d.to_string(), "1.5");
906 }
907
908 #[test]
909 fn test_leading_zeros() {
910 let d = Decimal::from_str("007").unwrap();
911 assert_eq!(d.to_string(), "7");
912
913 let d = Decimal::from_str("00.123").unwrap();
914 assert_eq!(d.to_string(), "0.123");
915 }
916
917 #[test]
920 fn test_into_bytes() {
921 let d = Decimal::from_str("123.456").unwrap();
922 let bytes_ref = d.as_bytes().to_vec();
923 let bytes_owned = d.into_bytes();
924 assert_eq!(bytes_ref, bytes_owned);
925 }
926
927 #[test]
928 fn test_clone() {
929 let d1 = Decimal::from_str("123.456").unwrap();
930 let d2 = d1.clone();
931 assert_eq!(d1, d2);
932 assert_eq!(d1.as_bytes(), d2.as_bytes());
933 }
934
935 #[test]
936 fn test_hash() {
937 use std::collections::HashSet;
938
939 let mut set = HashSet::new();
940 set.insert(Decimal::from_str("123.456").unwrap());
941 set.insert(Decimal::from_str("123.456").unwrap()); set.insert(Decimal::from_str("789.012").unwrap());
943
944 assert_eq!(set.len(), 2);
945 assert!(set.contains(&Decimal::from_str("123.456").unwrap()));
946 }
947
948 #[test]
949 fn test_debug_format() {
950 let d = Decimal::from_str("123.456").unwrap();
951 let debug_str = format!("{:?}", d);
952 assert!(debug_str.contains("Decimal"));
953 assert!(debug_str.contains("123.456"));
954 }
955
956 #[test]
957 fn test_ord_trait() {
958 use std::cmp::Ordering;
959
960 let a = Decimal::from_str("1").unwrap();
961 let b = Decimal::from_str("2").unwrap();
962 let c = Decimal::from_str("1").unwrap();
963
964 assert_eq!(a.cmp(&b), Ordering::Less);
965 assert_eq!(b.cmp(&a), Ordering::Greater);
966 assert_eq!(a.cmp(&c), Ordering::Equal);
967 }
968
969 #[test]
970 fn test_from_bytes_invalid() {
971 let result = Decimal::from_bytes(&[]);
973 assert!(result.is_err());
974
975 let result = Decimal::from_bytes(&[0x00]);
977 assert!(result.is_err());
978 }
979
980 #[test]
981 fn test_deserialize_from_string_number() {
982 let d: Decimal = serde_json::from_str("\"42\"").unwrap();
984 assert_eq!(d.to_string(), "42");
985
986 let d: Decimal = serde_json::from_str("\"-100\"").unwrap();
987 assert_eq!(d.to_string(), "-100");
988
989 let d: Decimal = serde_json::from_str("\"1.5e10\"").unwrap();
990 assert_eq!(d.to_string(), "15000000000");
991 }
992
993 #[test]
994 fn test_from_various_integer_types() {
995 assert_eq!(Decimal::from(0i32).to_string(), "0");
996 assert_eq!(Decimal::from(i32::MAX).to_string(), "2147483647");
997 assert_eq!(Decimal::from(i32::MIN).to_string(), "-2147483648");
998 assert_eq!(Decimal::from(i64::MAX).to_string(), "9223372036854775807");
999 assert_eq!(Decimal::from(i64::MIN).to_string(), "-9223372036854775808");
1000 }
1001
1002 #[test]
1003 fn test_precision_overflow() {
1004 let result = Decimal::from_str("1e20000");
1006 assert!(result.is_err());
1007 assert!(matches!(
1008 result.unwrap_err(),
1009 DecimalError::PrecisionOverflow
1010 ));
1011
1012 let result = Decimal::from_str("1e-20000");
1014 assert!(result.is_err());
1015 assert!(matches!(
1016 result.unwrap_err(),
1017 DecimalError::PrecisionOverflow
1018 ));
1019 }
1020
1021 #[test]
1022 fn test_all_zeros_variations() {
1023 let d = Decimal::from_str("0").unwrap();
1024 assert!(d.is_zero());
1025
1026 let d = Decimal::from_str("0.0").unwrap();
1027 assert!(d.is_zero());
1028
1029 let d = Decimal::from_str("00.00").unwrap();
1030 assert!(d.is_zero());
1031
1032 let d = Decimal::from_str("-0").unwrap();
1033 assert!(d.is_zero());
1034 }
1036
1037 #[test]
1040 fn test_rounding_all_nines() {
1041 let d = Decimal::with_precision_scale("99.999", Some(10), Some(2)).unwrap();
1043 assert_eq!(d.to_string(), "100");
1044
1045 let d = Decimal::with_precision_scale("9.99", Some(10), Some(1)).unwrap();
1047 assert_eq!(d.to_string(), "10");
1048
1049 let d = Decimal::with_precision_scale("999", Some(10), Some(-1)).unwrap();
1051 assert_eq!(d.to_string(), "1000");
1052 }
1053
1054 #[test]
1055 fn test_negative_scale_small_number() {
1056 let d = Decimal::with_precision_scale("4", Some(10), Some(-1)).unwrap();
1058 assert_eq!(d.to_string(), "0");
1059
1060 let d = Decimal::with_precision_scale("5", Some(10), Some(-1)).unwrap();
1062 assert_eq!(d.to_string(), "10");
1063
1064 let d = Decimal::with_precision_scale("-4", Some(10), Some(-1)).unwrap();
1066 assert_eq!(d.to_string(), "0");
1067
1068 let d = Decimal::with_precision_scale("-5", Some(10), Some(-1)).unwrap();
1070 assert_eq!(d.to_string(), "-10");
1071 }
1072
1073 #[test]
1074 fn test_precision_truncation() {
1075 let d = Decimal::with_precision_scale("123456", Some(3), Some(0)).unwrap();
1077 assert_eq!(d.to_string(), "456");
1078
1079 let d = Decimal::with_precision_scale("12345.67", Some(4), Some(2)).unwrap();
1081 assert_eq!(d.to_string(), "45.67");
1082 }
1083
1084 #[test]
1085 fn test_very_small_numbers() {
1086 let d = Decimal::from_str("0.000000001").unwrap();
1087 assert_eq!(d.to_string(), "0.000000001");
1088 assert!(d.is_positive());
1089
1090 let d = Decimal::from_str("-0.000000001").unwrap();
1091 assert_eq!(d.to_string(), "-0.000000001");
1092 assert!(d.is_negative());
1093 }
1094
1095 #[test]
1096 fn test_very_large_numbers() {
1097 let d = Decimal::from_str("999999999999999999999999999999").unwrap();
1098 assert_eq!(d.to_string(), "999999999999999999999999999999");
1099
1100 let d = Decimal::from_str("-999999999999999999999999999999").unwrap();
1101 assert_eq!(d.to_string(), "-999999999999999999999999999999");
1102 }
1103
1104 #[test]
1105 fn test_max_exponent_boundary() {
1106 let d = Decimal::from_str("1e16000").unwrap();
1108 assert!(d.is_positive());
1109
1110 let result = Decimal::from_str("1e17000");
1112 assert!(result.is_err());
1113 }
1114
1115 #[test]
1116 fn test_min_exponent_boundary() {
1117 let d = Decimal::from_str("1e-16000").unwrap();
1119 assert!(d.is_positive());
1120
1121 let result = Decimal::from_str("1e-17000");
1123 assert!(result.is_err());
1124 }
1125
1126 #[test]
1127 fn test_odd_digit_count() {
1128 let d = Decimal::from_str("12345").unwrap();
1130 assert_eq!(d.to_string(), "12345");
1131
1132 let d = Decimal::from_str("1").unwrap();
1133 assert_eq!(d.to_string(), "1");
1134
1135 let d = Decimal::from_str("123").unwrap();
1136 assert_eq!(d.to_string(), "123");
1137 }
1138
1139 #[test]
1140 fn test_negative_number_ordering() {
1141 let a = Decimal::from_str("-100").unwrap();
1143 let b = Decimal::from_str("-10").unwrap();
1144 let c = Decimal::from_str("-1").unwrap();
1145
1146 assert!(a < b);
1148 assert!(b < c);
1149
1150 assert!(a.as_bytes() < b.as_bytes());
1152 assert!(b.as_bytes() < c.as_bytes());
1153 }
1154
1155 #[test]
1156 fn test_from_bytes_unchecked_roundtrip() {
1157 let original = Decimal::from_str("123.456").unwrap();
1158 let bytes = original.as_bytes().to_vec();
1159 let restored = Decimal::from_bytes_unchecked(bytes);
1160 assert_eq!(original, restored);
1161 }
1162
1163 #[test]
1164 fn test_special_value_checks() {
1165 let d = Decimal::from_str("123.456").unwrap();
1166 assert!(!d.is_nan());
1167 assert!(!d.is_infinity());
1168 assert!(!d.is_pos_infinity());
1169 assert!(!d.is_neg_infinity());
1170 assert!(!d.is_special());
1171 assert!(d.is_finite());
1172 }
1173
1174 #[test]
1175 fn test_equality_and_hash_consistency() {
1176 use std::collections::HashMap;
1177
1178 let d1 = Decimal::from_str("123.456").unwrap();
1179 let d2 = Decimal::from_str("123.456").unwrap();
1180 let d3 = Decimal::from_str("123.457").unwrap();
1181
1182 assert_eq!(d1, d2);
1184 assert_ne!(d1, d3);
1185
1186 let mut map = HashMap::new();
1188 map.insert(d1.clone(), "first");
1189 map.insert(d2.clone(), "second"); assert_eq!(map.len(), 1);
1191 assert_eq!(map.get(&d1), Some(&"second"));
1192 }
1193
1194 #[test]
1195 fn test_scale_zero() {
1196 let d = Decimal::with_precision_scale("123.999", Some(10), Some(0)).unwrap();
1198 assert_eq!(d.to_string(), "124"); }
1200
1201 #[test]
1202 fn test_only_fractional_with_precision_scale() {
1203 let d = Decimal::with_precision_scale(".5", Some(10), Some(2)).unwrap();
1204 assert_eq!(d.to_string(), "0.5");
1205 }
1206
1207 #[test]
1208 fn test_default_impl() {
1209 let d = Decimal::default();
1210 assert!(d.is_zero());
1211 assert_eq!(d.to_string(), "0");
1212 }
1213
1214 #[test]
1215 fn test_precision_zero_integer_digits() {
1216 let d = Decimal::with_precision_scale("123.456", Some(2), Some(2)).unwrap();
1219 assert_eq!(d.to_string(), "0.46");
1220 }
1221
1222 #[test]
1223 fn test_negative_with_precision_truncation() {
1224 let d = Decimal::with_precision_scale("-123.456", Some(3), Some(2)).unwrap();
1226 assert_eq!(d.to_string(), "-3.46");
1227 }
1228
1229 #[test]
1230 fn test_invalid_sign_byte() {
1231 let result = Decimal::from_bytes(&[0x01, 0x40, 0x00, 0x12]);
1236 assert!(result.is_err());
1237
1238 let result = Decimal::from_bytes(&[0x7F, 0x40, 0x00, 0x12]);
1240 assert!(result.is_err());
1241
1242 let result = Decimal::from_bytes(&[0xFE, 0x40, 0x00, 0x12]);
1244 assert!(result.is_err());
1245 }
1246
1247 #[test]
1248 fn test_invalid_bcd_encoding() {
1249 let invalid_bytes = vec![
1253 0xFF, 0x80, 0x00, 0xAB, ];
1257 let result = Decimal::from_bytes(&invalid_bytes);
1258 assert!(result.is_err());
1259
1260 let invalid_bytes = vec![
1262 0xFF, 0x80, 0x00, 0xA1, ];
1266 let result = Decimal::from_bytes(&invalid_bytes);
1267 assert!(result.is_err());
1268
1269 let invalid_bytes = vec![
1271 0xFF, 0x80, 0x00, 0x1B, ];
1275 let result = Decimal::from_bytes(&invalid_bytes);
1276 assert!(result.is_err());
1277 }
1278
1279 #[test]
1280 fn test_reserved_exponent_positive() {
1281 let bytes_with_reserved_exp = vec![
1288 0xFF, 0xFF, 0xFF, 0x12, ];
1292 let result = Decimal::from_bytes(&bytes_with_reserved_exp);
1293 assert!(result.is_err());
1294
1295 let bytes_with_reserved_exp = vec![
1297 0xFF, 0xFF, 0xFE, 0x12, ];
1301 let result = Decimal::from_bytes(&bytes_with_reserved_exp);
1302 assert!(result.is_err());
1303 }
1304
1305 #[test]
1306 fn test_reserved_exponent_negative() {
1307 let bytes_with_reserved_exp = vec![
1312 0x00, 0x00, 0x00, 0x12, ];
1316 let result = Decimal::from_bytes(&bytes_with_reserved_exp);
1317 assert!(result.is_err());
1318 }
1319
1320 #[test]
1321 fn test_empty_mantissa_bytes() {
1322 let bytes_no_mantissa = vec![
1325 0xFF, 0x80, 0x00, ];
1329 let d = Decimal::from_bytes(&bytes_no_mantissa).unwrap();
1330 assert_eq!(d.to_string(), "0");
1331 }
1332
1333 #[cfg(feature = "rust_decimal")]
1336 mod rust_decimal_tests {
1337 use super::*;
1338
1339 #[test]
1340 fn test_from_rust_decimal() {
1341 use rust_decimal::Decimal as RustDecimal;
1342
1343 let rd = RustDecimal::new(12345, 2); let d: Decimal = rd.try_into().unwrap();
1345 assert_eq!(d.to_string(), "123.45");
1346 }
1347
1348 #[test]
1349 fn test_to_rust_decimal() {
1350 use rust_decimal::Decimal as RustDecimal;
1351
1352 let d = Decimal::from_str("123.45").unwrap();
1353 let rd: RustDecimal = (&d).try_into().unwrap();
1354 assert_eq!(rd.to_string(), "123.45");
1355 }
1356
1357 #[test]
1358 fn test_rust_decimal_roundtrip() {
1359 use rust_decimal::Decimal as RustDecimal;
1360
1361 let values = vec!["0", "1", "-1", "123.456", "-999.999", "0.001"];
1362
1363 for s in values {
1364 let d = Decimal::from_str(s).unwrap();
1365 let rd: RustDecimal = (&d).try_into().unwrap();
1366 let d2: Decimal = rd.try_into().unwrap();
1367 assert_eq!(d, d2, "Roundtrip failed for {}", s);
1368 }
1369 }
1370
1371 #[test]
1372 fn test_rust_decimal_arithmetic() {
1373 use rust_decimal::Decimal as RustDecimal;
1374
1375 let a = Decimal::from_str("100.50").unwrap();
1377 let b = Decimal::from_str("25.25").unwrap();
1378
1379 let ra: RustDecimal = (&a).try_into().unwrap();
1381 let rb: RustDecimal = (&b).try_into().unwrap();
1382 let sum = ra + rb;
1383
1384 let result: Decimal = sum.try_into().unwrap();
1386 assert_eq!(result.to_string(), "125.75");
1387 }
1388
1389 #[test]
1390 fn test_rust_decimal_from_owned() {
1391 use rust_decimal::Decimal as RustDecimal;
1392
1393 let d = Decimal::from_str("456.789").unwrap();
1395 let rd: RustDecimal = d.try_into().unwrap();
1396 assert_eq!(rd.to_string(), "456.789");
1397 }
1398
1399 #[test]
1400 fn test_rust_decimal_special_values_fail() {
1401 use rust_decimal::Decimal as RustDecimal;
1402
1403 let inf = Decimal::infinity();
1405 let result: Result<RustDecimal, _> = (&inf).try_into();
1406 assert!(result.is_err());
1407
1408 let nan = Decimal::nan();
1410 let result: Result<RustDecimal, _> = (&nan).try_into();
1411 assert!(result.is_err());
1412 }
1413 }
1414
1415 #[cfg(feature = "bigdecimal")]
1418 mod bigdecimal_tests {
1419 use super::*;
1420
1421 #[test]
1422 fn test_from_bigdecimal() {
1423 use bigdecimal::BigDecimal;
1424 use std::str::FromStr;
1425
1426 let bd = BigDecimal::from_str("123.45").unwrap();
1427 let d: Decimal = bd.try_into().unwrap();
1428 assert_eq!(d.to_string(), "123.45");
1429 }
1430
1431 #[test]
1432 fn test_to_bigdecimal() {
1433 use bigdecimal::BigDecimal;
1434
1435 let d = Decimal::from_str("123.45").unwrap();
1436 let bd: BigDecimal = (&d).try_into().unwrap();
1437 assert_eq!(bd.to_string(), "123.45");
1438 }
1439
1440 #[test]
1441 fn test_bigdecimal_roundtrip() {
1442 use bigdecimal::BigDecimal;
1443
1444 let values = vec!["0", "1", "-1", "123.456", "-999.999", "0.001"];
1445
1446 for s in values {
1447 let d = Decimal::from_str(s).unwrap();
1448 let bd: BigDecimal = (&d).try_into().unwrap();
1449 let d2: Decimal = bd.try_into().unwrap();
1450 assert_eq!(d, d2, "Roundtrip failed for {}", s);
1451 }
1452 }
1453
1454 #[test]
1455 fn test_bigdecimal_from_owned() {
1456 use bigdecimal::BigDecimal;
1457
1458 let d = Decimal::from_str("456.789").unwrap();
1460 let bd: BigDecimal = d.try_into().unwrap();
1461 assert_eq!(bd.to_string(), "456.789");
1462 }
1463
1464 #[test]
1465 fn test_bigdecimal_from_ref() {
1466 use bigdecimal::BigDecimal;
1467 use std::str::FromStr;
1468
1469 let bd = BigDecimal::from_str("789.012").unwrap();
1471 let d: Decimal = (&bd).try_into().unwrap();
1472 assert_eq!(d.to_string(), "789.012");
1473 }
1474
1475 #[test]
1476 fn test_bigdecimal_special_values_fail() {
1477 use bigdecimal::BigDecimal;
1478
1479 let inf = Decimal::infinity();
1481 let result: Result<BigDecimal, _> = (&inf).try_into();
1482 assert!(result.is_err());
1483
1484 let nan = Decimal::nan();
1486 let result: Result<BigDecimal, _> = (&nan).try_into();
1487 assert!(result.is_err());
1488 }
1489 }
1490}