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