Skip to main content

rsonpath_syntax/
num.rs

1//! JSON number types expressible in a JSONPath query.
2//!
3//! Exposes the [`JsonInt`] and [`JsonUInt`] types
4//! that can represent any numbers in the range [-2<sup>53</sup>+1, 2<sup>53</sup>-1],
5//! with the unsigned version additionally guaranteed to be non-negative. All operations
6//! implemented are automatically checked for over- and underflow.
7//!
8//! This is governed by the [I-JSON IETF specification](https://www.rfc-editor.org/rfc/rfc7493.html#section-2).
9//! All numbers appearing in a JSONPath query are required to be I-JSON conformant
10//! (see [RFC 2.1-4.1](https://www.ietf.org/archive/id/draft-ietf-jsonpath-base-21.html#section-2.1-4.1)).
11//! This includes index values, all values in slice selectors, and constants
12//! in filter comparison expressions.
13//!
14//! # Examples
15//! ```
16//! # use rsonpath_syntax::num::{JsonInt, JsonUInt};
17//! // An i32/u32 converts directly to JsonInt/JsonUInt.
18//! let a = JsonInt::from(-42);
19//! let b = JsonUInt::from(42);
20//! // i64/u64 has to be checked for overflow.
21//! let c = JsonInt::try_from(42_000_000_000_000_i64).expect("within range");
22//! let d = JsonInt::try_from(42_000_000_000_000_000_i64).expect_err("too large");
23//!
24//! assert_eq!(a.as_i64(), -42);
25//! assert_eq!(b.as_u64(), 42);
26//! assert_eq!(c.as_i64(), 42_000_000_000_000_i64);
27//! ```
28pub 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/// Signed interoperable JSON integer.
38///
39/// Provides an [IETF-conforming integer value](https://www.rfc-editor.org/rfc/rfc7493.html#section-2)
40/// Values are \[-2<sup>53</sup>+1, 2<sup>53</sup>-1].
41///
42/// All values in a JSONPath query are limited to this range for interoperability
43/// (see [RFC 2.1-4.1](https://www.ietf.org/archive/id/draft-ietf-jsonpath-base-21.html#section-2.1-4.1)).
44///
45/// The unsigned version is [`JsonUInt`].
46///
47/// # Examples
48/// ```
49/// # use rsonpath_syntax::num::JsonInt;
50/// let two = JsonInt::from(2);
51/// let zero = JsonInt::from(0);
52/// let negative = JsonInt::from(-2);
53///
54/// assert_eq!(two.as_i64(), 2);
55/// assert_eq!(zero.as_i64(), 0);
56/// assert_eq!(negative.as_i64(), -2);
57///
58/// let too_big = JsonInt::try_from(1_i64 << 53).expect_err("out of range");
59/// let too_small = JsonInt::try_from(-(1_i64 << 53)).expect_err("out of range");
60/// ```
61#[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/// Unsigned interoperable JSON integer.
66///
67/// Provides an [IETF-conforming integer value](https://www.rfc-editor.org/rfc/rfc7493.html#section-2)
68/// guaranteed to be non-negative. Values are \[0, (2<sup>53</sup>)-1].
69///
70/// All values in a JSONPath query are limited to the \[-2<sup>53</sup>+1, (2<sup>53</sup>)-1]
71/// range for interoperability
72/// (see [RFC 2.1-4.1](https://www.ietf.org/archive/id/draft-ietf-jsonpath-base-21.html#section-2.1-4.1)).
73/// Some, like array indices, are additionally restricted to the non-negative part.
74///
75/// The signed version is [`JsonInt`].
76///
77/// # Examples
78/// ```
79/// # use rsonpath_syntax::num::JsonUInt;
80/// let two = JsonUInt::from(2);
81/// let zero = JsonUInt::from(0);
82///
83/// assert_eq!(two.as_u64(), 2);
84/// assert_eq!(zero.as_u64(), 0);
85///
86/// let too_big = JsonUInt::try_from(1_u64 << 53).expect_err("out of range");
87/// ```
88#[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/// Unsigned interoperable JSON integer known to be non-zero.
93///
94/// Provides an [IETF-conforming integer value](https://www.rfc-editor.org/rfc/rfc7493.html#section-2)
95/// guaranteed to be positive. Values are \(0, (2<sup>53</sup>)-1].
96///
97/// All values in a JSONPath query are limited to the \[-2<sup>53</sup>+1, (2<sup>53</sup>)-1]
98/// range for interoperability
99/// (see [RFC 2.1-4.1](https://www.ietf.org/archive/id/draft-ietf-jsonpath-base-21.html#section-2.1-4.1)).
100/// Some, like array indices, are additionally restricted to the non-negative part, while
101/// indexing from the end of an array requires a positive value.
102///
103/// The zero-compatible version is [`JsonUInt`].
104///
105/// # Examples
106/// ```
107/// # use rsonpath_syntax::num::JsonNonZeroUInt;
108/// let two = JsonNonZeroUInt::try_from(2).expect("within range");
109/// assert_eq!(two.as_u64(), 2);
110///
111/// let zero = JsonNonZeroUInt::try_from(0).expect_err("out of range");
112/// let too_big = JsonNonZeroUInt::try_from(1_u64 << 53).expect_err("out of range");
113/// ```
114#[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/// IEEE 754 conformant floating-point number expressible in JSON.
119///
120/// These numbers behave as standard binary64 (double precision) numbers
121/// restricted as in [the JSON specification](https://www.rfc-editor.org/rfc/rfc7159#section-6),
122/// i.e. they cannot be NaN, +Inf, or -Inf.
123///
124/// These restrictions allow some "nice" properties - [`JsonFloat`] implements
125/// [`Eq`] and [`Ord`], as well as [`Hash`](std::hash::Hash), and its binary representation
126/// is the same as a regular [`f64`].
127///
128/// ## Integer conversions
129///
130/// Because of interoperability restrictions on [`JsonInt`], any [`JsonInt`] losslessly converts
131/// to a [`JsonFloat`] and back. Therefore, [`JsonInt`] is [`Into<JsonFloat>`](`Into`), and
132/// [`JsonFloat`] is [`TryInto<JsonInt>`], where the conversion succeeds if and only if
133/// the float is an exactly representable integer in the range \[-2<sup>53</sup>+1, (2<sup>53</sup>)-1].
134#[derive(Clone, Copy, Debug, PartialEq)]
135#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
136pub struct JsonFloat(f64);
137
138// This is correct since the allowed values for `JsonFloat` don't include NaNs or infinities.
139impl 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/// JSONPath numeric type - either a [`JsonInt`] or a [`JsonFloat`].
161///
162/// Note that this type is not normalized and an integer in the range
163/// \[-2<sup>53</sup>+1, (2<sup>53</sup>)-1] can be represented both as
164/// a [`JsonNumber::Int`] and as a [`JsonNumber::Float`].
165///
166/// Which type is produced when is a parser implementation detail.
167/// If you need to rely on integers always being represented as [`JsonNumber::Int`]
168/// you can use [`JsonNumber::normalize`], or manually inspect the underlying
169/// [`JsonFloat`] using [`JsonFloat::is_int`] and its [`TryInto<JsonInt>`] conversion.
170///
171/// ## Examples
172///
173/// ```
174/// # use rsonpath_syntax::num::{JsonNumber, JsonInt, JsonFloat};
175///
176/// let int = JsonInt::from(42);
177/// let float = JsonFloat::try_from(42.01).unwrap();
178///
179/// let num_int = JsonNumber::from(int);
180/// let num_float = JsonNumber::from(float);
181///
182/// assert_eq!(num_int, JsonNumber::Int(int));
183/// assert_eq!(num_float, JsonNumber::Float(float));
184/// assert_eq!("42", num_int.to_string());
185/// assert_eq!("42.01", num_float.to_string());
186/// ```
187#[derive(Clone, Copy, Debug)]
188#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
189pub enum JsonNumber {
190    /// A [`JsonInt`] number.
191    Int(JsonInt),
192    /// A [`JsonFloat`] number.
193    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
238/// The upper unsigned inclusive bound on JSON integers (2<sup>53</sup>-1).
239const JSON_UINT_UPPER_LIMIT: u64 = (1 << 53) - 1;
240/// The upper inclusive bound on JSON integers (2<sup>53</sup>-1).
241const JSON_INT_UPPER_LIMIT: i64 = (1 << 53) - 1;
242/// The lower inclusive bound on JSON integers (-2<sup>53</sup>+1).
243const JSON_INT_LOWER_LIMIT: i64 = -(1 << 53) + 1;
244
245impl JsonInt {
246    /// A constant value of zero. Equivalent to [`JsonInt::default`](`Default::default`).
247    ///
248    /// # Examples
249    /// ```
250    /// # use rsonpath_syntax::num::JsonInt;
251    /// assert_eq!(JsonInt::ZERO.as_i64(), 0);
252    /// ```
253    pub const ZERO: Self = Self::new(0);
254
255    /// A constant value of one.
256    ///
257    /// # Examples
258    /// ```
259    /// # use rsonpath_syntax::num::JsonInt;
260    /// assert_eq!(JsonInt::ONE.as_i64(), 1);
261    /// ```
262    pub const ONE: Self = Self::new(1);
263
264    /// A constant for the smallest expressible value.
265    ///
266    /// # Examples
267    /// ```
268    /// # use rsonpath_syntax::num::JsonInt;
269    /// let min_i64 = -(1 << 53) + 1;
270    ///
271    /// assert_eq!(JsonInt::MIN.as_i64(), min_i64);
272    /// assert_eq!(JsonInt::try_from(min_i64).expect("within range"), JsonInt::MIN);
273    /// ```
274    pub const MIN: Self = Self::new(JSON_INT_LOWER_LIMIT);
275
276    /// A constant for the largest expressible value.
277    ///
278    /// # Examples
279    /// ```
280    /// # use rsonpath_syntax::num::JsonInt;
281    /// let max_i64 = (1 << 53) - 1;
282    ///
283    /// assert_eq!(JsonInt::MAX.as_i64(), max_i64);
284    /// assert_eq!(JsonInt::try_from(max_i64).expect("within range"), JsonInt::MAX);
285    /// ```
286    pub const MAX: Self = Self::new(JSON_INT_UPPER_LIMIT);
287
288    /// Create a new value from a [`i64`].
289    #[must_use]
290    const fn new(index: i64) -> Self {
291        Self(index)
292    }
293
294    /// Increase the integer by one.
295    ///
296    /// # Errors
297    /// Will return `Err` if the increment causes the [`JsonInt`] to exceed
298    /// the upper limit of [`JsonInt::MAX`].
299    ///
300    /// # Examples
301    /// ```
302    /// # use rsonpath_syntax::num::JsonInt;
303    /// let mut x = JsonInt::ZERO;
304    /// x.try_increment().expect("within range");
305    /// assert_eq!(x.as_i64(), 1);
306    ///
307    /// let mut y = JsonInt::MIN;
308    /// y.try_increment().expect("within range");
309    /// assert_eq!(y.as_i64(), -(1 << 53) + 2);
310    ///
311    /// JsonInt::MAX.try_increment().expect_err("out of range");
312    /// ```
313    #[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    /// Return the value stored as a regular [`i64`].
325    ///
326    /// # Examples
327    /// ```
328    /// # use rsonpath_syntax::num::JsonInt;
329    /// let val = JsonInt::from(42);
330    /// assert_eq!(val.as_i64(), 42);
331    /// ```
332    #[must_use]
333    #[inline(always)]
334    pub const fn as_i64(&self) -> i64 {
335        self.0
336    }
337
338    /// Return the negation of the value.
339    ///
340    /// This is guaranteed to succeed, as the valid range is symmetrical.
341    /// ```
342    /// # use rsonpath_syntax::num::JsonInt;
343    /// let x = JsonInt::from(-42);
344    /// assert_eq!(x.neg().as_i64(), 42);
345    /// ```
346    #[must_use]
347    #[inline(always)]
348    pub const fn neg(&self) -> Self {
349        Self(-self.0)
350    }
351
352    /// Return the absolute value of this integer as a [`JsonUInt`].
353    ///
354    /// This is guaranteed to succeed, as the valid range is symmetrical.
355    ///
356    /// # Examples
357    /// ```
358    /// # use rsonpath_syntax::num::{JsonInt, JsonUInt};
359    /// let pos = JsonInt::from(42);
360    /// let neg = JsonInt::from(-42);
361    /// assert_eq!(neg.abs().as_u64(), 42);
362    /// assert_eq!(pos.abs().as_u64(), 42);
363    /// ```
364    #[inline(always)]
365    #[must_use]
366    pub const fn abs(&self) -> JsonUInt {
367        JsonUInt(self.0.unsigned_abs())
368    }
369}
370
371impl JsonUInt {
372    /// A constant value of zero. Equivalent to [`JsonUInt::default`](`Default::default`).
373    ///
374    /// # Examples
375    /// ```
376    /// # use rsonpath_syntax::num::JsonUInt;
377    /// assert_eq!(JsonUInt::ZERO.as_u64(), 0);
378    /// ```
379    pub const ZERO: Self = Self::new(0);
380
381    /// A constant value of one.
382    ///
383    /// # Examples
384    /// ```
385    /// # use rsonpath_syntax::num::JsonUInt;
386    /// assert_eq!(JsonUInt::ONE.as_u64(), 1);
387    /// ```
388    pub const ONE: Self = Self::new(1);
389
390    /// A constant for the largest expressible value.
391    ///
392    /// # Examples
393    /// ```
394    /// # use rsonpath_syntax::num::JsonUInt;
395    /// let max_u64 = (1 << 53) - 1;
396    ///
397    /// assert_eq!(JsonUInt::MAX.as_u64(), max_u64);
398    /// assert_eq!(JsonUInt::try_from(max_u64).expect("within range"), JsonUInt::MAX);
399    /// ```
400    pub const MAX: Self = Self::new(JSON_UINT_UPPER_LIMIT);
401
402    /// Create a new value from a [`u64`].
403    #[must_use]
404    const fn new(index: u64) -> Self {
405        Self(index)
406    }
407
408    /// Increase the integer by one.
409    ///
410    /// # Errors
411    /// Will return `Err` if the increment causes the [`JsonUInt`] to exceed
412    /// the upper limit of [`JsonUInt::MAX`].
413    ///
414    /// # Examples
415    /// ```
416    /// # use rsonpath_syntax::num::JsonUInt;
417    /// let mut x = JsonUInt::ZERO;
418    /// x.try_increment().expect("within range");
419    /// JsonUInt::MAX.try_increment().expect_err("out of range");
420    ///
421    /// assert_eq!(x.as_u64(), 1);
422    /// ```
423    #[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    /// Return the negation of the value as a [`JsonInt`].
435    ///
436    /// This is guaranteed to succeed, as the valid range is symmetrical.
437    /// ```
438    /// # use rsonpath_syntax::num::{JsonInt, JsonUInt};
439    /// let x = JsonUInt::from(42);
440    /// let y = JsonInt::from(-42);
441    /// assert_eq!(x.neg(), y);
442    /// ```
443    #[must_use]
444    #[inline(always)]
445    pub const fn neg(&self) -> JsonInt {
446        JsonInt(-(self.0 as i64))
447    }
448
449    /// Return the value stored as a regular [`u64`].
450    ///
451    /// # Examples
452    /// ```
453    /// # use rsonpath_syntax::num::JsonUInt;
454    /// let val = JsonUInt::from(42);
455    /// assert_eq!(val.as_u64(), 42);
456    /// ```
457    #[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    /// Return the value stored as a [`NonZeroU64`].
471    ///
472    /// # Examples
473    /// ```
474    /// # use rsonpath_syntax::num::JsonNonZeroUInt;
475    /// # use std::num::NonZeroU64;
476    /// let val = JsonNonZeroUInt::try_from(42).unwrap();
477    /// assert_eq!(val.as_non_zero_u64(), NonZeroU64::new(42).unwrap());
478    /// ```
479    #[must_use]
480    #[inline(always)]
481    pub const fn as_non_zero_u64(&self) -> NonZeroU64 {
482        self.0
483    }
484
485    /// Return the value stored as a [`u64`].
486    ///
487    /// # Examples
488    /// ```
489    /// # use rsonpath_syntax::num::JsonNonZeroUInt;
490    /// let val = JsonNonZeroUInt::try_from(42).unwrap();
491    /// assert_eq!(val.as_u64(), 42);
492    /// ```
493    #[must_use]
494    #[inline(always)]
495    pub const fn as_u64(&self) -> u64 {
496        self.0.get()
497    }
498}
499
500impl JsonFloat {
501    /// A constant value of zero. Equivalent to [`JsonFloat::default`](`Default::default`).
502    ///
503    /// # Examples
504    /// ```
505    /// # use rsonpath_syntax::num::JsonFloat;
506    /// assert_eq!(JsonFloat::ZERO.as_f64(), 0.0);
507    /// ```
508    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    /// Return the value stored as a [`f64`].
516    ///
517    /// # Examples
518    /// ```
519    /// # use rsonpath_syntax::num::JsonFloat;
520    /// let val = JsonFloat::try_from(3.14).unwrap();
521    /// assert_eq!(val.as_f64(), 3.14);
522    /// ```
523    #[inline]
524    #[must_use]
525    pub fn as_f64(&self) -> f64 {
526        self.0
527    }
528
529    /// Check if this float is an equivalent of some [`JsonInt`].
530    ///
531    /// The range of valid [`JsonInt`] is exactly representable as [`JsonFloat`] values.
532    /// This function returns true if the float is one of those valid values, i.e. an
533    /// integer and in the [`JsonInt`] bounds.
534    ///
535    /// ## Examples
536    /// ```
537    /// # use rsonpath_syntax::num::JsonFloat;
538    ///
539    /// let f1 = JsonFloat::try_from(3.0).unwrap();
540    /// let f2 = JsonFloat::try_from(3.14).unwrap();
541    /// let f3 = JsonFloat::try_from(1e54).unwrap();
542    ///
543    /// assert!(f1.is_int());
544    /// assert!(!f2.is_int());
545    /// assert!(!f3.is_int());
546    /// ```
547    #[inline]
548    #[must_use]
549    pub fn is_int(&self) -> bool {
550        JsonInt::try_from(*self).is_ok()
551    }
552}
553
554impl JsonNumber {
555    /// A constant value of zero, as an integer.
556    /// Equivalent to [`JsonNumber::default`](`Default::default`) and
557    /// [`JsonNumber::from(JsonInt::ZERO)`](`JsonNumber::Int`).
558    ///
559    /// # Examples
560    /// ```
561    /// # use rsonpath_syntax::num::{JsonNumber, JsonInt};
562    /// assert_eq!(JsonNumber::ZERO, JsonNumber::Int(JsonInt::ZERO));
563    /// ```
564    pub const ZERO: Self = Self::Int(JsonInt(0));
565
566    /// Normalize a [`JsonNumber`] so that valid [`JsonInt`] value is represented
567    /// by [`JsonNumber::Int`].
568    ///
569    /// The parser is allowed to represent a normal JSON integer (e.g. 17) as an
570    /// equivalent JSON float (17.0). Calling `normalize` ensures all values
571    /// representable by a [`JsonInt`] are indeed represented as such.
572    ///
573    /// ## Examples
574    ///
575    /// ```
576    /// # use rsonpath_syntax::num::{JsonNumber, JsonInt, JsonFloat};
577    ///
578    /// // Creating a JsonNumber from a JsonFloat always gives JsonNumber::Float.
579    /// let f1 = JsonFloat::try_from(17.0).unwrap();
580    /// let nf1 = JsonNumber::from(f1);
581    /// assert_eq!(nf1, JsonNumber::Float(f1));
582    /// // Normalizing will give us an integer representation, when possible.
583    /// assert_eq!(nf1.normalize(), JsonNumber::Int(17.into()));
584    ///
585    /// // If the float is an integer within range normalization will succeed.
586    /// let f2 = JsonFloat::try_from(1e15).unwrap();
587    /// let nf2 = JsonNumber::from(f2);
588    /// assert_eq!(nf2, JsonNumber::Float(f2));
589    /// assert_eq!(nf2.normalize(), JsonNumber::Int(1_000_000_000_000_000_i64.try_into().unwrap()));
590    ///
591    /// // An int is an int, and remains so under normalization.
592    /// let i1 = JsonInt::from(42);
593    /// let ni1 = JsonNumber::from(i1);
594    /// assert_eq!(ni1, JsonNumber::Int(i1));
595    /// assert_eq!(ni1.normalize(), JsonNumber::Int(i1));
596    ///
597    /// // A float that is not an int remains the same when normalized.
598    /// let f3 = JsonFloat::try_from(3.14).unwrap();
599    /// let nf3 = JsonNumber::from(f3);
600    /// assert_eq!(nf3, JsonNumber::Float(f3));
601    /// assert_eq!(nf3.normalize(), JsonNumber::Float(f3));
602    ///
603    /// // A float that is an int, but outside of the interoperable JsonInt range,
604    /// // is not normalized.
605    /// let f4 = JsonFloat::try_from(1e120).unwrap();
606    /// let nf4 = JsonNumber::from(f4);
607    /// assert_eq!(nf4, JsonNumber::Float(f4));
608    /// assert_eq!(nf4.normalize(), JsonNumber::Float(f4));
609    /// ```
610    #[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    // i32 is always in the range (-2^53, 2^53)
653    #[inline]
654    fn from(value: i32) -> Self {
655        Self::new(i64::from(value))
656    }
657}
658
659impl From<u32> for JsonInt {
660    // u32 is always in the range (-2^53, 2^53)
661    #[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        // This is always safe due to the type invariant bounds.
678        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    // u32 is always in the range [0, 2^53)
722    #[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        // Safe cast since JsonUInt::MAX is lower than i64::MAX.
752        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            // u64 would work but i64 gives us a better error message for negative values.
776            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    // NonZeroU32 is always in the range (0, 2^53)
784    #[inline]
785    fn from(value: NonZeroU32) -> Self {
786        Self::new(NonZeroU64::from(value))
787    }
788}
789
790impl From<NonZeroU64> for JsonNonZeroUInt {
791    // NonZeroU64 is always in the range (0, 2^53)
792    #[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            // u64 would work but i64 gives us a better error message for negative values.
867            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        // At this point the fractional part must be 0.0, so the value is *an* integer.
882        // We need to check that it is within bounds of JsonInt. This is correct
883        // only because JsonInt bounds are guaranteed to be interoperable with f64,
884        // so every value within is exactly representable as a f64.
885        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        // This conversion is now guaranteed to be lossless.
894        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    /* Fact #1: parsing floats is hard.
935    * Fact #2: grammar accepted by `f64::from_str` is slightly different from the
936    *          JSONPath grammar for floats.
937    * Fact #3: I have little interest in rewriting the close to 2,000 lines of code
938    *          of Rust's `dec2flt` to incorporate those differences.
939    *
940    * The grammars accepted by Rust and JSON are, respectively:
941      ; Rust f64::from_str
942      Float  ::= Sign? ( 'inf' | 'infinity' | 'nan' | Number )
943      Number ::= ( Digit+ |
944                   Digit+ '.' Digit* |
945                   Digit* '.' Digit+ ) Exp?
946      Exp    ::= 'e' Sign? Digit+
947      Sign   ::= [+-]
948      Digit  ::= [0-9]
949
950      ; JSON
951      Number ::= (Int | "-0") Frac? Exp?
952      Int    ::= "0" |
953                 ("-"? Digit1 Digit*)
954      Frac   ::= "." Digit+
955      Exp    ::= "e" Sign? Digit+
956      Sign   ::= [+-]
957      Digit  ::= [0-9]
958      Digit1 ::= [1-9]
959
960    * Here are all the differences:
961    * 1) 'inf', 'infinity', and 'nan' are acceptable only in Rust.
962    * 2) Rust allows an explicit leading `+`, JSON does not.
963    * 3) Rust allows an empty integer part, e.g. '.14' as equivalent to '0.14'; JSON does not.
964    * 4) Rust allows an empty decimal part, e.g. '3.' as equivalent to '3.0'; JSON does not.
965    * 5) Leading zeroes of the integral part are accepted only in Rust.
966    *
967    * Both accept the exponent char as either lower or uppercase.
968    * Since Rust's grammar is more general than JSON (L(JSON) \subset L(Rust))
969    * we can use Rust's parser and enforce stricter JSON rules independently.
970    *
971    * To satisfy all restrictions, we parse with Rust first and then:
972    * - enforce the result is not Inf or NaN (rule 1);
973    * - enforce the string does not begin with '+' (rule 2);
974    * - check if the decimal period exists (Rust guarantees there is at most one),
975    *   and enforce it is both preceded and followed by a digit (rules 3 and 4);
976    * - enforce there are no leading zeroes (rule 5).
977    *
978    * Performance-wise this is not ideal - we're effectively inspecting the string twice.
979    * But without access into the `f64::from_str` black-box the only solution would be
980    * to rewrite the routine here and add the restrictions, and we rejected that at the start.
981    * If Rust ever exposes an API to create an f64 out of the mantissa and exponent then it might
982    * be possible - the hardest bits of the parsing routine happen after these are actually extracted
983    * from the string. See: https://github.com/rust-lang/rust/blob/master/library/core/src/num/dec2flt/mod.rs
984    */
985
986    #[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                // Rule 1.
995                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                    // Rule 3. The case `before == "+"` is checked later.
1000                    if before.is_empty() || before == "-" {
1001                        return Err(Self::Err::nothing_before_decimal_point(s));
1002                    }
1003                    // Rule 4.
1004                    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                // Rule 2.
1011                if first_c == '+' {
1012                    return Err(Self::Err::leading_plus_sign(s));
1013                }
1014                // Skip the leading minus if it exists.
1015                let s_no_sign = if first_c == '-' { chars.as_str() } else { s };
1016                // Rule 5.
1017                // Check for leading zeroes. We strip the first zero from the front and check what's left.
1018                // The only acceptable case is that the next character is not a digit.
1019                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            // Remember that all floats valid in JSON are also accepted by Rust,
1027            // so this is *definitely* not a valid JSON float.
1028            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
1047// Not the smartest implementation, but a working one.
1048// Every valid JsonInt is a valid JsonFloat, so parse a JsonFloat first and then try to canonicalize
1049// the JsonNumber.
1050impl 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)] // Detects 3.14 as PI, that's not we want for tests.
1276        #[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}