1pub mod error;
29
30use crate::num::error::{JsonFloatConvertError, JsonFloatParseError, JsonIntOverflowError, JsonIntParseError};
31use std::{
32 fmt::{self, Display, Formatter},
33 num::{NonZeroU32, NonZeroU64},
34 str::FromStr,
35};
36
37#[derive(Clone, Copy, Default, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
62#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
63pub struct JsonInt(i64);
64
65#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
89#[derive(Clone, Copy, Default, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
90pub struct JsonUInt(u64);
91
92#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
115#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
116pub struct JsonNonZeroUInt(NonZeroU64);
117
118#[derive(Clone, Copy, Debug, PartialEq)]
135#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
136pub struct JsonFloat(f64);
137
138impl Eq for JsonFloat {}
140impl PartialOrd for JsonFloat {
141 #[inline(always)]
142 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
143 Some(self.cmp(other))
144 }
145}
146impl Ord for JsonFloat {
147 #[inline(always)]
148 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
149 self.0.partial_cmp(&other.0).expect("JsonFloat never NaN")
150 }
151}
152
153impl std::hash::Hash for JsonFloat {
154 #[inline(always)]
155 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
156 self.0.to_bits().hash(state);
157 }
158}
159
160#[derive(Clone, Copy, Debug)]
188#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
189#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
190pub enum JsonNumber {
191 Int(JsonInt),
193 Float(JsonFloat),
195}
196
197impl PartialEq for JsonNumber {
198 #[inline]
199 fn eq(&self, other: &Self) -> bool {
200 match (self.normalize(), other.normalize()) {
201 (Self::Int(l0), Self::Int(r0)) => l0 == r0,
202 (Self::Float(l0), Self::Float(r0)) => l0 == r0,
203 _ => false,
204 }
205 }
206}
207
208impl Eq for JsonNumber {}
209
210impl std::hash::Hash for JsonNumber {
211 #[inline]
212 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
213 match self.normalize() {
214 Self::Int(i) => (0, i).hash(state),
215 Self::Float(f) => (1, f).hash(state),
216 }
217 }
218}
219
220impl PartialOrd for JsonNumber {
221 #[inline(always)]
222 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
223 Some(self.cmp(other))
224 }
225}
226
227impl Ord for JsonNumber {
228 #[inline]
229 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
230 match (self, other) {
231 (Self::Int(i1), Self::Int(i2)) => i1.cmp(i2),
232 (Self::Int(i), Self::Float(f)) => JsonFloat::from(*i).cmp(f),
233 (Self::Float(f), Self::Int(i)) => f.cmp(&JsonFloat::from(*i)),
234 (Self::Float(f1), Self::Float(f2)) => f1.cmp(f2),
235 }
236 }
237}
238
239const JSON_UINT_UPPER_LIMIT: u64 = (1 << 53) - 1;
241const JSON_INT_UPPER_LIMIT: i64 = (1 << 53) - 1;
243const JSON_INT_LOWER_LIMIT: i64 = -(1 << 53) + 1;
245
246impl JsonInt {
247 pub const ZERO: Self = Self::new(0);
255
256 pub const ONE: Self = Self::new(1);
264
265 pub const MIN: Self = Self::new(JSON_INT_LOWER_LIMIT);
276
277 pub const MAX: Self = Self::new(JSON_INT_UPPER_LIMIT);
288
289 #[must_use]
291 const fn new(index: i64) -> Self {
292 Self(index)
293 }
294
295 #[inline]
315 pub fn try_increment(&mut self) -> Result<(), JsonIntOverflowError> {
316 let new_index = self.0 + 1;
317 if new_index <= JSON_INT_UPPER_LIMIT {
318 self.0 = new_index;
319 Ok(())
320 } else {
321 Err(JsonIntOverflowError::int_neg_overflow(new_index))
322 }
323 }
324
325 #[must_use]
334 #[inline(always)]
335 pub const fn as_i64(&self) -> i64 {
336 self.0
337 }
338
339 #[must_use]
348 #[inline(always)]
349 pub const fn neg(&self) -> Self {
350 Self(-self.0)
351 }
352
353 #[inline(always)]
366 #[must_use]
367 pub const fn abs(&self) -> JsonUInt {
368 JsonUInt(self.0.unsigned_abs())
369 }
370}
371
372impl JsonUInt {
373 pub const ZERO: Self = Self::new(0);
381
382 pub const ONE: Self = Self::new(1);
390
391 pub const MAX: Self = Self::new(JSON_UINT_UPPER_LIMIT);
402
403 #[must_use]
405 const fn new(index: u64) -> Self {
406 Self(index)
407 }
408
409 #[inline]
425 pub fn try_increment(&mut self) -> Result<(), JsonIntOverflowError> {
426 let new_index = self.0 + 1;
427 if new_index <= JSON_UINT_UPPER_LIMIT {
428 self.0 = new_index;
429 Ok(())
430 } else {
431 Err(JsonIntOverflowError::uint_pos_overflow(new_index))
432 }
433 }
434
435 #[must_use]
445 #[inline(always)]
446 pub const fn neg(&self) -> JsonInt {
447 JsonInt(-(self.0 as i64))
448 }
449
450 #[must_use]
459 #[inline(always)]
460 pub const fn as_u64(&self) -> u64 {
461 self.0
462 }
463}
464
465impl JsonNonZeroUInt {
466 #[must_use]
467 const fn new(value: NonZeroU64) -> Self {
468 Self(value)
469 }
470
471 #[must_use]
481 #[inline(always)]
482 pub const fn as_non_zero_u64(&self) -> NonZeroU64 {
483 self.0
484 }
485
486 #[must_use]
495 #[inline(always)]
496 pub const fn as_u64(&self) -> u64 {
497 self.0.get()
498 }
499}
500
501impl JsonFloat {
502 fn new(x: f64) -> Self {
503 debug_assert!(x.is_finite());
504 Self(x)
505 }
506
507 #[inline]
516 #[must_use]
517 pub fn as_f64(&self) -> f64 {
518 self.0
519 }
520
521 #[inline]
540 #[must_use]
541 pub fn is_int(&self) -> bool {
542 JsonInt::try_from(*self).is_ok()
543 }
544}
545
546impl JsonNumber {
547 #[inline]
592 #[must_use]
593 pub fn normalize(&self) -> Self {
594 match *self {
595 Self::Int(x) => Self::Int(x),
596 Self::Float(x) => match JsonInt::try_from(x) {
597 Ok(int) => Self::Int(int),
598 Err(_) => Self::Float(x),
599 },
600 }
601 }
602}
603
604impl TryFrom<i64> for JsonInt {
605 type Error = JsonIntOverflowError;
606
607 #[inline]
608 fn try_from(value: i64) -> Result<Self, Self::Error> {
609 if value > JSON_INT_UPPER_LIMIT {
610 Err(JsonIntOverflowError::int_pos_overflow(value))
611 } else if value < JSON_INT_LOWER_LIMIT {
612 Err(JsonIntOverflowError::int_neg_overflow(value))
613 } else {
614 Ok(Self::new(value))
615 }
616 }
617}
618
619impl TryFrom<u64> for JsonInt {
620 type Error = JsonIntOverflowError;
621
622 #[inline]
623 fn try_from(value: u64) -> Result<Self, Self::Error> {
624 if value > i64::MAX as u64 {
625 Err(JsonIntOverflowError::int_pos_overflow_u(value))
626 } else {
627 Self::try_from(value as i64)
628 }
629 }
630}
631
632impl From<i32> for JsonInt {
633 #[inline]
635 fn from(value: i32) -> Self {
636 Self::new(i64::from(value))
637 }
638}
639
640impl From<u32> for JsonInt {
641 #[inline]
643 fn from(value: u32) -> Self {
644 Self::new(i64::from(value))
645 }
646}
647
648impl From<JsonInt> for i64 {
649 #[inline(always)]
650 fn from(value: JsonInt) -> Self {
651 value.0
652 }
653}
654
655impl From<JsonUInt> for JsonInt {
656 #[inline(always)]
657 fn from(value: JsonUInt) -> Self {
658 Self::new(value.0 as i64)
660 }
661}
662
663impl FromStr for JsonInt {
664 type Err = JsonIntParseError;
665
666 #[inline]
667 fn from_str(s: &str) -> Result<Self, Self::Err> {
668 match i64::from_str(s) {
669 Ok(x) => x.try_into().map_err(|e| Self::Err::parse_conversion_err(s, &e)),
670 Err(err) => Err(Self::Err::int_parse_error(s, err.kind())),
671 }
672 }
673}
674
675impl TryFrom<u64> for JsonUInt {
676 type Error = JsonIntOverflowError;
677
678 #[inline]
679 fn try_from(value: u64) -> Result<Self, Self::Error> {
680 if value > JSON_UINT_UPPER_LIMIT {
681 Err(JsonIntOverflowError::uint_pos_overflow(value))
682 } else {
683 Ok(Self::new(value))
684 }
685 }
686}
687
688impl TryFrom<i64> for JsonUInt {
689 type Error = JsonIntOverflowError;
690
691 #[inline]
692 fn try_from(value: i64) -> Result<Self, Self::Error> {
693 if value < 0 {
694 Err(JsonIntOverflowError::negative_uint(value))
695 } else {
696 Self::try_from(value as u64)
697 }
698 }
699}
700
701impl From<u32> for JsonUInt {
702 #[inline]
704 fn from(value: u32) -> Self {
705 Self::new(u64::from(value))
706 }
707}
708
709impl TryFrom<i32> for JsonUInt {
710 type Error = JsonIntOverflowError;
711
712 #[inline]
713 fn try_from(value: i32) -> Result<Self, Self::Error> {
714 if value < 0 {
715 Err(JsonIntOverflowError::negative_uint(i64::from(value)))
716 } else {
717 Ok(Self::from(value as u32))
718 }
719 }
720}
721
722impl From<JsonUInt> for u64 {
723 #[inline(always)]
724 fn from(value: JsonUInt) -> Self {
725 value.0
726 }
727}
728
729impl From<JsonUInt> for i64 {
730 #[inline(always)]
731 fn from(value: JsonUInt) -> Self {
732 value.0 as Self
734 }
735}
736
737impl TryFrom<JsonInt> for JsonUInt {
738 type Error = JsonIntOverflowError;
739
740 #[inline]
741 fn try_from(value: JsonInt) -> Result<Self, Self::Error> {
742 if value.0 < 0 {
743 Err(JsonIntOverflowError::negative_uint(value.0))
744 } else {
745 Ok(Self::new(value.0 as u64))
746 }
747 }
748}
749
750impl FromStr for JsonUInt {
751 type Err = JsonIntParseError;
752
753 #[inline]
754 fn from_str(s: &str) -> Result<Self, Self::Err> {
755 match i64::from_str(s) {
756 Ok(x) => x.try_into().map_err(|e| Self::Err::parse_conversion_err(s, &e)),
758 Err(err) => Err(Self::Err::uint_parse_error(s, err.kind())),
759 }
760 }
761}
762
763impl From<NonZeroU32> for JsonNonZeroUInt {
764 #[inline]
766 fn from(value: NonZeroU32) -> Self {
767 Self::new(NonZeroU64::from(value))
768 }
769}
770
771impl From<NonZeroU64> for JsonNonZeroUInt {
772 #[inline]
774 fn from(value: NonZeroU64) -> Self {
775 Self::new(value)
776 }
777}
778
779impl TryFrom<u32> for JsonNonZeroUInt {
780 type Error = JsonIntOverflowError;
781
782 #[inline]
783 fn try_from(value: u32) -> Result<Self, Self::Error> {
784 Self::try_from(u64::from(value))
785 }
786}
787
788impl TryFrom<i32> for JsonNonZeroUInt {
789 type Error = JsonIntOverflowError;
790
791 #[inline]
792 fn try_from(value: i32) -> Result<Self, Self::Error> {
793 Self::try_from(i64::from(value))
794 }
795}
796
797impl TryFrom<u64> for JsonNonZeroUInt {
798 type Error = JsonIntOverflowError;
799
800 #[inline]
801 fn try_from(value: u64) -> Result<Self, Self::Error> {
802 if value > JSON_UINT_UPPER_LIMIT {
803 Err(JsonIntOverflowError::uint_pos_overflow(value))
804 } else if let Some(x) = NonZeroU64::new(value) {
805 Ok(Self(x))
806 } else {
807 Err(JsonIntOverflowError::zero_non_zero_uint())
808 }
809 }
810}
811
812impl TryFrom<i64> for JsonNonZeroUInt {
813 type Error = JsonIntOverflowError;
814
815 #[inline]
816 fn try_from(value: i64) -> Result<Self, Self::Error> {
817 if value < 0 {
818 Err(JsonIntOverflowError::negative_uint(value))
819 } else {
820 Self::try_from(value as u64)
821 }
822 }
823}
824
825impl TryFrom<JsonUInt> for JsonNonZeroUInt {
826 type Error = JsonIntOverflowError;
827
828 #[inline]
829 fn try_from(value: JsonUInt) -> Result<Self, Self::Error> {
830 Self::try_from(value.0)
831 }
832}
833
834impl From<JsonNonZeroUInt> for JsonUInt {
835 #[inline]
836 fn from(value: JsonNonZeroUInt) -> Self {
837 Self::new(value.0.get())
838 }
839}
840
841impl FromStr for JsonNonZeroUInt {
842 type Err = JsonIntParseError;
843
844 #[inline]
845 fn from_str(s: &str) -> Result<Self, Self::Err> {
846 match i64::from_str(s) {
847 Ok(x) => x.try_into().map_err(|e| Self::Err::parse_conversion_err(s, &e)),
849 Err(err) => Err(Self::Err::non_zero_uint_parse_error(s, err.kind())),
850 }
851 }
852}
853
854impl TryFrom<JsonFloat> for JsonInt {
855 type Error = JsonIntOverflowError;
856
857 #[inline]
858 fn try_from(value: JsonFloat) -> Result<Self, Self::Error> {
859 if value.0.fract() != 0.0 {
860 return Err(JsonIntOverflowError::fractional(value.0));
861 }
862 let int_value = value.0.trunc();
867 if int_value < JSON_INT_LOWER_LIMIT as f64 {
868 return Err(JsonIntOverflowError::int_float_neg_overflow(value.0));
869 }
870 if int_value > JSON_INT_UPPER_LIMIT as f64 {
871 return Err(JsonIntOverflowError::int_float_pos_overflow(value.0));
872 }
873
874 Ok(Self(int_value as i64))
876 }
877}
878
879impl From<JsonInt> for JsonFloat {
880 #[inline]
881 fn from(value: JsonInt) -> Self {
882 Self::new(value.0 as f64)
883 }
884}
885
886impl TryFrom<f32> for JsonFloat {
887 type Error = JsonFloatConvertError;
888
889 #[inline]
890 fn try_from(value: f32) -> Result<Self, Self::Error> {
891 if value.is_finite() {
892 Ok(Self::new(f64::from(value)))
893 } else {
894 Err(JsonFloatConvertError::infinite_or_nan(f64::from(value)))
895 }
896 }
897}
898
899impl TryFrom<f64> for JsonFloat {
900 type Error = JsonFloatConvertError;
901
902 #[inline]
903 fn try_from(value: f64) -> Result<Self, Self::Error> {
904 if value.is_finite() {
905 Ok(Self::new(value))
906 } else {
907 Err(JsonFloatConvertError::infinite_or_nan(value))
908 }
909 }
910}
911
912impl FromStr for JsonFloat {
913 type Err = JsonFloatParseError;
914
915 #[inline]
968 fn from_str(s: &str) -> Result<Self, Self::Err> {
969 match f64::from_str(s) {
970 Ok(x) => {
971 assert!(!s.is_empty()); if x.is_nan() || x.is_infinite() {
974 return Err(Self::Err::infinite_or_nan(s));
975 }
976 if let Some((before, after)) = s.split_once('.') {
977 if before.is_empty() || before == "-" {
979 return Err(Self::Err::nothing_before_decimal_point(s));
980 }
981 if after.is_empty() || after.starts_with(['e', 'E']) {
983 return Err(Self::Err::nothing_after_decimal_point(s));
984 }
985 }
986 let mut chars = s.chars();
987 let first_c = chars.next().expect("s is non-empty");
988 if first_c == '+' {
990 return Err(Self::Err::leading_plus_sign(s));
991 }
992 let s_no_sign = if first_c == '-' { chars.as_str() } else { s };
994 if let Some(rest) = s_no_sign.strip_prefix('0') {
998 if matches!(rest.chars().next(), Some('0'..='9')) {
999 return Err(Self::Err::leading_zeros(s));
1000 }
1001 }
1002 Ok(Self(x))
1003 }
1004 Err(_) => Err(Self::Err::f64_parse_error(s)),
1007 }
1008 }
1009}
1010
1011impl From<JsonInt> for JsonNumber {
1012 #[inline]
1013 fn from(value: JsonInt) -> Self {
1014 Self::Int(value)
1015 }
1016}
1017
1018impl From<JsonFloat> for JsonNumber {
1019 #[inline]
1020 fn from(value: JsonFloat) -> Self {
1021 Self::Float(value)
1022 }
1023}
1024
1025impl Display for JsonInt {
1026 #[inline]
1027 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1028 write!(f, "{}", self.0)
1029 }
1030}
1031
1032impl Display for JsonUInt {
1033 #[inline]
1034 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1035 write!(f, "{}", self.0)
1036 }
1037}
1038
1039impl Display for JsonNonZeroUInt {
1040 #[inline]
1041 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1042 write!(f, "{}", self.0)
1043 }
1044}
1045
1046impl Display for JsonFloat {
1047 #[inline]
1048 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1049 write!(f, "{}", self.0)
1050 }
1051}
1052
1053impl Display for JsonNumber {
1054 #[inline]
1055 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1056 match self {
1057 Self::Int(int) => int.fmt(f),
1058 Self::Float(flt) => flt.fmt(f),
1059 }
1060 }
1061}
1062
1063#[cfg(feature = "arbitrary")]
1064#[cfg_attr(docsrs, doc(cfg(feature = "arbitrary")))]
1065impl<'a> arbitrary::Arbitrary<'a> for JsonInt {
1066 #[inline]
1067 fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
1068 let val = u.int_in_range(JSON_INT_LOWER_LIMIT..=JSON_INT_UPPER_LIMIT)?;
1069
1070 Ok(Self::new(val))
1071 }
1072}
1073
1074#[cfg(feature = "arbitrary")]
1075#[cfg_attr(docsrs, doc(cfg(feature = "arbitrary")))]
1076impl<'a> arbitrary::Arbitrary<'a> for JsonUInt {
1077 #[inline]
1078 fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
1079 let val = u.int_in_range(0..=JSON_UINT_UPPER_LIMIT)?;
1080
1081 Ok(Self::new(val))
1082 }
1083}
1084
1085#[cfg(feature = "arbitrary")]
1086#[cfg_attr(docsrs, doc(cfg(feature = "arbitrary")))]
1087impl<'a> arbitrary::Arbitrary<'a> for JsonNonZeroUInt {
1088 #[inline]
1089 fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
1090 let val = u.int_in_range(1..=JSON_UINT_UPPER_LIMIT)?;
1091
1092 Ok(Self::new(NonZeroU64::new(val).expect("range starts at 1")))
1093 }
1094}
1095
1096#[cfg(feature = "arbitrary")]
1097#[cfg_attr(docsrs, doc(cfg(feature = "arbitrary")))]
1098impl<'a> arbitrary::Arbitrary<'a> for JsonFloat {
1099 #[inline]
1100 fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
1101 let val = u.arbitrary::<f64>()?;
1102 let val = if val.is_nan() {
1104 0.0
1105 } else if val.is_infinite() {
1106 (0.0_f64).copysign(val)
1107 } else {
1108 val
1109 };
1110
1111 Ok(Self(val))
1112 }
1113}
1114
1115#[cfg(test)]
1116mod tests {
1117 use super::*;
1118 use pretty_assertions::assert_eq;
1119
1120 #[test]
1121 fn int_upper_limit_sanity_check() {
1122 assert_eq!(JSON_INT_UPPER_LIMIT, (1 << 53) - 1);
1123 assert_eq!(JSON_INT_UPPER_LIMIT, 9_007_199_254_740_991);
1124 }
1125
1126 #[test]
1127 fn int_lower_limit_sanity_check() {
1128 assert_eq!(JSON_INT_LOWER_LIMIT, -(1 << 53) + 1);
1129 assert_eq!(JSON_INT_LOWER_LIMIT, -9_007_199_254_740_991);
1130 assert_eq!(JSON_INT_LOWER_LIMIT, -JSON_INT_UPPER_LIMIT);
1131 }
1132
1133 #[test]
1134 fn uint_upper_limit_sanity_check() {
1135 assert_eq!(JSON_UINT_UPPER_LIMIT, (1 << 53) - 1);
1136 assert_eq!(JSON_UINT_UPPER_LIMIT, 9_007_199_254_740_991);
1137 assert_eq!(JSON_INT_UPPER_LIMIT, JSON_UINT_UPPER_LIMIT as i64);
1138 }
1139
1140 #[test]
1141 fn int_lower_limit_try_from_check() {
1142 let min = JsonInt::try_from(JSON_INT_LOWER_LIMIT).expect("JSON int lower_limit should be convertible.");
1143 let err = JsonInt::try_from(JSON_INT_LOWER_LIMIT - 1)
1144 .expect_err("Values below JSON int lower_limit should not be convertible.");
1145 assert_eq!(min.as_i64(), JSON_INT_LOWER_LIMIT);
1146 assert_eq!(
1147 err.to_string(),
1148 "value -9007199254740992 is below the range of JsonInt values [-9007199254740991..9007199254740991]"
1149 );
1150 }
1151
1152 #[test]
1153 fn int_upper_limit_try_from_check() {
1154 let max = JsonInt::try_from(JSON_INT_UPPER_LIMIT).expect("JSON int upper_limit should be convertible.");
1155 let err = JsonInt::try_from(JSON_INT_UPPER_LIMIT + 1)
1156 .expect_err("Values in excess of JSON int upper_limit should not be convertible.");
1157 assert_eq!(max.as_i64(), JSON_INT_UPPER_LIMIT);
1158 assert_eq!(
1159 err.to_string(),
1160 "value 9007199254740992 is above the range of JsonInt values [-9007199254740991..9007199254740991]"
1161 );
1162 }
1163
1164 #[test]
1165 fn uint_upper_limit_try_from_check() {
1166 let max = JsonUInt::try_from(JSON_UINT_UPPER_LIMIT).expect("JSON uint upper_limit should be convertible.");
1167 let err = JsonUInt::try_from(JSON_UINT_UPPER_LIMIT + 1)
1168 .expect_err("Values in excess of JSON uint upper_limit should not be convertible.");
1169 assert_eq!(max.as_u64(), JSON_UINT_UPPER_LIMIT);
1170 assert_eq!(
1171 err.to_string(),
1172 "value 9007199254740992 is above the range of JsonUInt values [0..9007199254740991]"
1173 );
1174 }
1175
1176 #[test]
1177 fn non_zero_uint_try_from_zero_check() {
1178 let err_i32 = JsonNonZeroUInt::try_from(0_i32).expect_err("zero should not be convertible");
1179 let err_u32 = JsonNonZeroUInt::try_from(0_u32).expect_err("zero should not be convertible");
1180 let err_i64 = JsonNonZeroUInt::try_from(0_i64).expect_err("zero should not be convertible");
1181 let err_u64 = JsonNonZeroUInt::try_from(0_u64).expect_err("zero should not be convertible");
1182 assert_eq!(
1183 err_i32.to_string(),
1184 "attempt to convert a zero value into a JsonNonZeroUInt"
1185 );
1186 assert_eq!(
1187 err_u32.to_string(),
1188 "attempt to convert a zero value into a JsonNonZeroUInt"
1189 );
1190 assert_eq!(
1191 err_i64.to_string(),
1192 "attempt to convert a zero value into a JsonNonZeroUInt"
1193 );
1194 assert_eq!(
1195 err_u64.to_string(),
1196 "attempt to convert a zero value into a JsonNonZeroUInt"
1197 );
1198 }
1199
1200 #[test]
1201 fn parse_int_from_empty() {
1202 let err = JsonInt::from_str("").expect_err("empty string is not valid");
1203 assert_eq!(
1204 err.to_string(),
1205 "string '' is not a valid representation of a JSON integer"
1206 );
1207 }
1208
1209 #[test]
1210 fn parse_int_underflow() {
1211 let err = JsonInt::from_str("-9007199254740992").expect_err("out of range");
1212 assert_eq!(
1213 err.to_string(),
1214 "string '-9007199254740992' represents a value below the range of JsonInt values [-9007199254740991..9007199254740991]"
1215 );
1216 }
1217
1218 #[test]
1219 fn parse_int_overflow() {
1220 let err = JsonInt::from_str("9007199254740992").expect_err("out of range");
1221 assert_eq!(
1222 err.to_string(),
1223 "string '9007199254740992' represents a value above the range of JsonInt values [-9007199254740991..9007199254740991]"
1224 );
1225 }
1226
1227 #[test]
1228 fn parse_int_from_invalid_characters() {
1229 let err = JsonInt::from_str("42+7").expect_err("not a valid integer");
1230 assert_eq!(
1231 err.to_string(),
1232 "string '42+7' is not a valid representation of a JSON integer"
1233 );
1234 }
1235
1236 #[test]
1237 fn parse_uint_from_empty() {
1238 let err = JsonUInt::from_str("").expect_err("empty string is not valid");
1239 assert_eq!(
1240 err.to_string(),
1241 "string '' is not a valid representation of a JSON integer"
1242 );
1243 }
1244
1245 #[test]
1246 fn parse_uint_from_negative() {
1247 let err = JsonUInt::from_str("-42").expect_err("out of range");
1248 assert_eq!(
1249 err.to_string(),
1250 "string '-42' represents a value below the range of JsonUInt values [0..9007199254740991]"
1251 );
1252 }
1253
1254 #[test]
1255 fn parse_uint_overflow() {
1256 let err = JsonUInt::from_str("9007199254740992").expect_err("out of range");
1257 assert_eq!(
1258 err.to_string(),
1259 "string '9007199254740992' represents a value above the range of JsonUInt values [0..9007199254740991]"
1260 );
1261 }
1262
1263 #[test]
1264 fn parse_uint_from_invalid_characters() {
1265 let err = JsonUInt::from_str("42+7").expect_err("not a valid integer");
1266 assert_eq!(
1267 err.to_string(),
1268 "string '42+7' is not a valid representation of a JSON integer"
1269 );
1270 }
1271
1272 #[test]
1273 fn parse_non_zero_uint_from_zero() {
1274 let err = JsonNonZeroUInt::from_str("0").expect_err("not a non-zero integer");
1275 assert_eq!(
1276 err.to_string(),
1277 "string '0' represents a zero value, which is not a valid JsonNonZeroUInt"
1278 )
1279 }
1280
1281 #[test]
1282 fn convert_large_float_to_int() {
1283 let float = JsonFloat::try_from(1e15).unwrap();
1284 let int = JsonInt::try_from(float).expect("should succeed");
1285 assert_eq!(int.as_i64(), 1_000_000_000_000_000);
1286 }
1287
1288 mod json_float_parse {
1289 use super::*;
1290 use pretty_assertions::assert_eq;
1291 use test_case::test_case;
1292
1293 #[allow(clippy::approx_constant)] #[test_case("0.0", 0.0; "0d0")]
1295 #[test_case("0.0e+000000000000000000000", 0.0; "0d0ep000000000000000000000")]
1296 #[test_case("0.0E+000000000000000000000", 0.0; "0d0Uep000000000000000000000")]
1297 #[test_case("-0.0", -0.0; "m0d0")]
1298 #[test_case("3.14", 3.14; "3d142")]
1299 #[test_case("-3.14", -3.14; "m3d142")]
1300 #[test_case("3.14159265358979323846264338327950288", std::f64::consts::PI; "pi")]
1301 #[test_case("-3.00000000000000000000000000000000000000000000000", -3.0; "m3d00000000000000000000000000000000000000000000000")]
1302 #[test_case("-3.14e53", -3.14e53; "m3d14e53")]
1303 #[test_case("-3.14e+53", -3.14e53; "m3d14ep53")]
1304 #[test_case("-3.14e-53", -3.14e-53; "m3d14em53")]
1305 #[test_case("-3.14e-153", -3.14e-153; "m3d14em153")]
1306 #[test_case("42", 42.0; "42")]
1307 fn valid_float_string(str: &str, expected: f64) {
1308 let float = JsonFloat::from_str(str).expect("should parse");
1309 assert_eq!(float.as_f64(), expected);
1310 }
1311
1312 #[test_case("abc")]
1313 #[test_case("0xFF")]
1314 #[test_case("3,14")]
1315 #[test_case("3.14F-20")]
1316 #[test_case("3.3.3")]
1317 #[test_case(".")]
1318 #[test_case(".e30"; "de30")]
1319 #[test_case("e30")]
1320 fn invalid_float_strings_that_even_rust_rejects(str: &str) {
1321 let err = JsonFloat::from_str(str).expect_err("should not parse");
1322 let expected = format!("string '{str}' is not a valid representation of a float");
1323 assert_eq!(err.to_string(), expected);
1324 }
1325
1326 #[test_case("nan"; "nan lowercase")]
1327 #[test_case("NaN"; "NaN mixed case")]
1328 #[test_case("NAN"; "NAN uppercase")]
1329 #[test_case("-nan"; "minus nan lowercase")]
1330 #[test_case("-NaN"; "minus nan mixed case")]
1331 #[test_case("-NAN"; "minus nan uppercase")]
1332 #[test_case("inf"; "inf")]
1333 #[test_case("Inf"; "inf mixed case")]
1334 #[test_case("INF"; "inf uppercase")]
1335 #[test_case("-inf"; "minus inf")]
1336 #[test_case("-Inf"; "minus inf mixed case")]
1337 #[test_case("-INF"; "minus inf uppercase")]
1338 #[test_case("infinity"; "infinity mixed case")]
1339 #[test_case("Infinity"; "infinity")]
1340 #[test_case("INFINITY"; "infinity uppercase")]
1341 #[test_case("-infinity"; "minus infinity")]
1342 #[test_case("-Infinity"; "minus infinity mixed case")]
1343 #[test_case("-INFINITY"; "minus infinity uppercase")]
1344 fn invalid_float_strings_infinity_or_nan(str: &str) {
1345 let err = JsonFloat::from_str(str).expect_err("should not parse");
1346 let expected = format!("string '{str}' is not a valid JsonFloat as it is not a finite number");
1347 assert_eq!(err.to_string(), expected);
1348 }
1349
1350 #[test_case(".14"; "d14")]
1351 #[test_case("-.14"; "md14")]
1352 #[test_case(".0")]
1353 #[test_case(".14e53")]
1354 #[test_case(".00000e53")]
1355 fn invalid_float_strings_nothing_before_decimal_point(str: &str) {
1356 let err = JsonFloat::from_str(str).expect_err("should not parse");
1357 let expected = format!("missing digits before the decimal point in '{str}'");
1358 assert_eq!(err.to_string(), expected);
1359 }
1360
1361 #[test_case("14."; "14d")]
1362 #[test_case("-14."; "m14d")]
1363 #[test_case("-0.")]
1364 #[test_case("14.e53")]
1365 #[test_case("0.e53")]
1366 fn invalid_float_strings_nothing_after_decimal_point(str: &str) {
1367 let err = JsonFloat::from_str(str).expect_err("should not parse");
1368 let expected = format!("missing digits after the decimal point in '{str}'");
1369 assert_eq!(err.to_string(), expected);
1370 }
1371
1372 #[test_case("+3.14")]
1373 #[test_case("+3.14e53")]
1374 fn invalid_float_strings_leading_plus_sign(str: &str) {
1375 let err = JsonFloat::from_str(str).expect_err("should not parse");
1376 let expected = format!("string '{str}' includes a leading plus sign");
1377 assert_eq!(err.to_string(), expected);
1378 }
1379
1380 #[test_case("00.0"; "00d0")]
1381 #[test_case("-00.0"; "m00d0")]
1382 #[test_case("00"; "00")]
1383 #[test_case("00000000000")]
1384 #[test_case("-00"; "m00")]
1385 #[test_case("-00000000000"; "m00000000000")]
1386 #[test_case("03.14"; "03d14")]
1387 #[test_case("-03.14"; "m03d14")]
1388 #[test_case("03e14"; "03e14")]
1389 #[test_case("-03e14"; "m03e14")]
1390 #[test_case("00e14"; "00e14")]
1391 #[test_case("-00e14"; "m00e14")]
1392 fn invalid_float_strings_leading_zeros(str: &str) {
1393 let err = JsonFloat::from_str(str).expect_err("should not parse");
1394 let expected = format!("string '{str}' includes leading zeros");
1395 assert_eq!(err.to_string(), expected);
1396 }
1397 }
1398
1399 mod proptests {
1400 use super::super::*;
1401 use proptest::prelude::*;
1402
1403 proptest! {
1404 #[test]
1405 fn int_roundtrip(value in JSON_INT_LOWER_LIMIT..JSON_INT_UPPER_LIMIT) {
1406 let json_int = JsonInt::try_from(value).expect("within range");
1407 assert_eq!(json_int.as_i64(), value);
1408 }
1409
1410 #[test]
1411 fn uint_roundtrip(value in 0..JSON_UINT_UPPER_LIMIT) {
1412 let json_uint = JsonUInt::try_from(value).expect("within range");
1413 assert_eq!(json_uint.as_u64(), value);
1414 }
1415
1416 #[test]
1417 fn int_string_roundtrip(value in JSON_INT_LOWER_LIMIT..JSON_INT_UPPER_LIMIT) {
1418 let string = value.to_string();
1419 let json_int = JsonInt::from_str(&string).expect("valid string");
1420 assert_eq!(string, json_int.to_string())
1421 }
1422
1423 #[test]
1424 fn uint_string_roundtrip(value in 0..JSON_UINT_UPPER_LIMIT) {
1425 let string = value.to_string();
1426 let json_int = JsonUInt::from_str(&string).expect("valid string");
1427 assert_eq!(string, json_int.to_string())
1428 }
1429
1430 #[test]
1431 fn int_increment(value in JSON_INT_LOWER_LIMIT..(JSON_INT_UPPER_LIMIT - 1)) {
1432 let mut json_int = JsonInt::try_from(value).expect("within range");
1433 json_int.try_increment().expect("at most one below limit");
1434 assert_eq!(json_int.as_i64(), value + 1);
1435 }
1436
1437 #[test]
1438 fn uint_increment(value in 0..(JSON_UINT_UPPER_LIMIT - 1)) {
1439 let mut json_uint = JsonUInt::try_from(value).expect("within range");
1440 json_uint.try_increment().expect("at most one below limit");
1441 assert_eq!(json_uint.as_u64(), value + 1);
1442 }
1443 }
1444 }
1445}