jzon/
number.rs

1use std::{ ops, fmt, f32, f64 };
2use std::convert::{TryFrom, Infallible};
3use std::num::{FpCategory, TryFromIntError};
4use crate::util::grisu2;
5use crate::util::print_dec;
6
7/// NaN value represented in `Number` type. NaN is equal to itself.
8pub const NAN: Number = Number {
9    category: NAN_MASK,
10    mantissa: 0,
11    exponent: 0
12};
13
14const NEGATIVE: u8 = 0;
15const POSITIVE: u8 = 1;
16const NAN_MASK: u8 = !1;
17
18/// Number representation used inside `JsonValue`. You can easily convert
19/// the `Number` type into native Rust number types and back, or use the
20/// equality operator with another number type.
21///
22/// ```
23/// # use jzon::number::Number;
24/// let foo: Number = 3.14.into();
25/// let bar: f64 = foo.into();
26///
27/// assert_eq!(foo, 3.14);
28/// assert_eq!(bar, 3.14);
29/// ```
30///
31/// More often than not you will deal with `JsonValue::Number` variant that
32/// wraps around this type, instead of using the methods here directly.
33#[derive(Copy, Clone, Debug)]
34pub struct Number {
35    // A byte describing the sign and NaN-ness of the number.
36    //
37    // category == 0 (NEGATIVE constant)         -> negative sign
38    // category == 1 (POSITIVE constant)         -> positive sign
39    // category >  1 (matches NAN_MASK constant) -> NaN
40    category: u8,
41
42    // Decimal exponent, analog to `e` notation in string form.
43    exponent: i16,
44
45    // Integer base before sign and exponent applied.
46    mantissa: u64,
47}
48
49impl Number {
50    /// Construct a new `Number` from parts. This can't create a NaN value.
51    ///
52    /// ```
53    /// # use jzon::number::Number;
54    /// let pi = unsafe { Number::from_parts_unchecked(true, 3141592653589793, -15) };
55    ///
56    /// assert_eq!(pi, 3.141592653589793);
57    /// ```
58    ///
59    /// While this method is marked unsafe, it doesn't actually perform any unsafe operations.
60    /// THe goal of the 'unsafe' is to deter from using this method in favor of its safe equivalent
61    /// `from_parts`, at least in context when the associated performance cost is negligible.
62    #[inline]
63    pub unsafe fn from_parts_unchecked(positive: bool, mantissa: u64, exponent: i16) -> Self {
64        Number {
65            category: positive as u8,
66            exponent: exponent,
67            mantissa: mantissa,
68        }
69    }
70
71    /// Construct a new `Number` from parts, stripping unnecessary trailing zeroes.
72    /// This can't create a NaN value.
73    ///
74    /// ```
75    /// # use jzon::number::Number;
76    /// let one = Number::from_parts(true, 1000, -3);
77    /// let (positive, mantissa, exponent) = one.as_parts();
78    ///
79    /// assert_eq!(true, positive);
80    /// assert_eq!(1, mantissa);
81    /// assert_eq!(0, exponent);
82    /// ```
83    #[inline]
84    pub fn from_parts(positive: bool, mut mantissa: u64, mut exponent: i16) -> Self {
85        while exponent < 0 && mantissa % 10 == 0 {
86            exponent += 1;
87            mantissa /= 10;
88        }
89        unsafe { Number::from_parts_unchecked(positive, mantissa, exponent) }
90    }
91
92    /// Reverse to `from_parts` - obtain parts from an existing `Number`.
93    ///
94    /// ```
95    /// # use jzon::number::Number;
96    /// let pi = Number::from(3.141592653589793);
97    /// let (positive, mantissa, exponent) = pi.as_parts();
98    ///
99    /// assert_eq!(positive, true);
100    /// assert_eq!(mantissa, 3141592653589793);
101    /// assert_eq!(exponent, -15);
102    /// ```
103    #[inline]
104    pub fn as_parts(&self) -> (bool, u64, i16) {
105        (self.category == POSITIVE, self.mantissa, self.exponent)
106    }
107
108    #[inline]
109    pub fn is_sign_positive(&self) -> bool {
110        self.category == POSITIVE
111    }
112
113    #[inline]
114    pub fn is_zero(&self) -> bool {
115        self.mantissa == 0 && !self.is_nan()
116    }
117
118    #[inline]
119    pub fn is_nan(&self) -> bool {
120        self.category & NAN_MASK != 0
121    }
122
123    /// Test if the number is NaN or has a zero value.
124    #[inline]
125    pub fn is_empty(&self) -> bool {
126        self.mantissa == 0 || self.is_nan()
127    }
128
129    /// Obtain an integer at a fixed decimal point. This is useful for
130    /// converting monetary values and doing arithmetic on them without
131    /// rounding errors introduced by floating point operations.
132    ///
133    /// Will return `None` if `Number` is negative or a NaN.
134    ///
135    /// ```
136    /// # use jzon::number::Number;
137    /// let price_a = Number::from(5.99);
138    /// let price_b = Number::from(7);
139    /// let price_c = Number::from(10.2);
140    ///
141    /// assert_eq!(price_a.as_fixed_point_u64(2), Some(599));
142    /// assert_eq!(price_b.as_fixed_point_u64(2), Some(700));
143    /// assert_eq!(price_c.as_fixed_point_u64(2), Some(1020));
144    /// ```
145    pub fn as_fixed_point_u64(&self, point: u16) -> Option<u64> {
146        if self.category != POSITIVE {
147            return None;
148        }
149
150        let e_diff = point as i16 + self.exponent;
151
152        Some(if e_diff == 0 {
153            self.mantissa
154        } else if e_diff < 0 {
155            self.mantissa.wrapping_div(decimal_power(-e_diff as u16))
156        } else {
157            self.mantissa.wrapping_mul(decimal_power(e_diff as u16))
158        })
159    }
160
161    /// Analog to `as_fixed_point_u64`, except returning a signed
162    /// `i64`, properly handling negative numbers.
163    ///
164    /// ```
165    /// # use jzon::number::Number;
166    /// let balance_a = Number::from(-1.49);
167    /// let balance_b = Number::from(42);
168    ///
169    /// assert_eq!(balance_a.as_fixed_point_i64(2), Some(-149));
170    /// assert_eq!(balance_b.as_fixed_point_i64(2), Some(4200));
171    /// ```
172    pub fn as_fixed_point_i64(&self, point: u16) -> Option<i64> {
173        if self.is_nan() {
174            return None;
175        }
176
177        let num = if self.is_sign_positive() {
178            self.mantissa as i64
179        } else {
180            -(self.mantissa as i64)
181        };
182
183        let e_diff = point as i16 + self.exponent;
184
185        Some(if e_diff == 0 {
186            num
187        } else if e_diff < 0 {
188            num.wrapping_div(decimal_power(-e_diff as u16) as i64)
189        } else {
190            num.wrapping_mul(decimal_power(e_diff as u16) as i64)
191        })
192    }
193}
194
195impl PartialEq for Number {
196    #[inline]
197    fn eq(&self, other: &Number) -> bool {
198        if self.is_zero() && other.is_zero()
199        || self.is_nan()  && other.is_nan() {
200            return true;
201        }
202
203        if self.category != other.category {
204            return false;
205        }
206
207        let e_diff = self.exponent - other.exponent;
208
209        if e_diff == 0 {
210            return self.mantissa == other.mantissa;
211        } else if e_diff > 0 {
212            let power = decimal_power(e_diff as u16);
213
214            self.mantissa.wrapping_mul(power) == other.mantissa
215        } else {
216            let power = decimal_power(-e_diff as u16);
217
218            self.mantissa == other.mantissa.wrapping_mul(power)
219        }
220
221    }
222}
223
224impl fmt::Display for Number {
225    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
226        unsafe {
227            if self.is_nan() {
228                return f.write_str("nan")
229            }
230            let (positive, mantissa, exponent) = self.as_parts();
231            let mut buf = Vec::new();
232            print_dec::write(&mut buf, positive, mantissa, exponent).unwrap();
233            f.write_str(&String::from_utf8_unchecked(buf))
234        }
235    }
236}
237
238fn exponentiate_f64(n: f64, e: i16) -> f64 {
239    static CACHE_POWERS: [f64; 23] = [
240          1.0,    1e1,    1e2,    1e3,    1e4,    1e5,    1e6,    1e7,
241          1e8,    1e9,   1e10,   1e11,   1e12,   1e13,   1e14,   1e15,
242         1e16,   1e17,   1e18,   1e19,   1e20,   1e21,   1e22
243    ];
244
245    if e >= 0 {
246        let index = e as usize;
247
248        n * if index < 23 {
249            CACHE_POWERS[index]
250        } else {
251            10f64.powf(index as f64)
252        }
253    } else {
254        let index = -e as usize;
255
256        n / if index < 23 {
257            CACHE_POWERS[index]
258        } else {
259            10f64.powf(index as f64)
260        }
261    }
262}
263
264
265fn exponentiate_f32(n: f32, e: i16) -> f32 {
266    static CACHE_POWERS: [f32; 23] = [
267          1.0,    1e1,    1e2,    1e3,    1e4,    1e5,    1e6,    1e7,
268          1e8,    1e9,   1e10,   1e11,   1e12,   1e13,   1e14,   1e15,
269         1e16,   1e17,   1e18,   1e19,   1e20,   1e21,   1e22
270    ];
271
272    if e >= 0 {
273        let index = e as usize;
274
275        n * if index < 23 {
276            CACHE_POWERS[index]
277        } else {
278            10f32.powf(index as f32)
279        }
280    } else {
281        let index = -e as usize;
282
283        n / if index < 23 {
284            CACHE_POWERS[index]
285        } else {
286            10f32.powf(index as f32)
287        }
288    }
289}
290
291impl From<Number> for f64 {
292    fn from(num: Number) -> f64 {
293        if num.is_nan() { return f64::NAN; }
294
295        let mut n = num.mantissa as f64;
296        let mut e = num.exponent;
297
298        if e < -308 {
299            n = exponentiate_f64(n, e + 308);
300            e = -308;
301        }
302
303        let f = exponentiate_f64(n, e);
304        if num.is_sign_positive() { f } else { -f }
305    }
306}
307
308impl From<Number> for f32 {
309    fn from(num: Number) -> f32 {
310        if num.is_nan() { return f32::NAN; }
311
312        let mut n = num.mantissa as f32;
313        let mut e = num.exponent;
314
315        if e < -127 {
316            n = exponentiate_f32(n, e + 127);
317            e = -127;
318        }
319
320        let f = exponentiate_f32(n, e);
321        if num.is_sign_positive() { f } else { -f }
322    }
323}
324
325impl From<f64> for Number {
326    fn from(float: f64) -> Number {
327        match float.classify() {
328            FpCategory::Infinite | FpCategory::Nan => return NAN,
329            _ => {}
330        }
331
332        if !float.is_sign_positive() {
333            let (mantissa, exponent) = grisu2::convert(-float);
334
335            Number::from_parts(false, mantissa, exponent)
336        } else {
337            let (mantissa, exponent) = grisu2::convert(float);
338
339            Number::from_parts(true, mantissa, exponent)
340        }
341    }
342}
343
344impl From<f32> for Number {
345    fn from(float: f32) -> Number {
346        match float.classify() {
347            FpCategory::Infinite | FpCategory::Nan => return NAN,
348            _ => {}
349        }
350
351        if !float.is_sign_positive() {
352            let (mantissa, exponent) = grisu2::convert(-float as f64);
353
354            Number::from_parts(false, mantissa, exponent)
355        } else {
356            let (mantissa, exponent) = grisu2::convert(float as f64);
357
358            Number::from_parts(true, mantissa, exponent)
359        }
360    }
361}
362
363impl PartialEq<f64> for Number {
364    fn eq(&self, other: &f64) -> bool {
365        f64::from(*self) == *other
366    }
367}
368
369impl PartialEq<f32> for Number {
370    fn eq(&self, other: &f32) -> bool {
371        f32::from(*self) == *other
372    }
373}
374
375impl PartialEq<Number> for f64 {
376    fn eq(&self, other: &Number) -> bool {
377        f64::from(*other) == *self
378    }
379}
380
381impl PartialEq<Number> for f32 {
382    fn eq(&self, other: &Number) -> bool {
383        f32::from(*other) == *self
384    }
385}
386
387/// Error type generated when trying to convert a `Number` into an
388/// integer of inadequate size.
389#[derive(Clone, Copy)]
390pub struct NumberOutOfScope;
391
392impl From<Infallible> for NumberOutOfScope {
393    fn from(_: Infallible) -> NumberOutOfScope {
394        NumberOutOfScope
395    }
396}
397
398impl From<TryFromIntError> for NumberOutOfScope {
399    fn from(_: TryFromIntError) -> NumberOutOfScope {
400        NumberOutOfScope
401    }
402}
403
404macro_rules! impl_unsigned {
405    ($( $t:ty ),*) => ($(
406        impl From<$t> for Number {
407            #[inline]
408            fn from(num: $t) -> Number {
409                Number {
410                    category: POSITIVE,
411                    exponent: 0,
412                    mantissa: num as u64,
413                }
414            }
415        }
416
417        impl TryFrom<Number> for $t {
418            type Error = NumberOutOfScope;
419
420            fn try_from(num: Number) -> Result<Self, Self::Error> {
421                let (positive, mantissa, exponent) = num.as_parts();
422
423                if !positive || exponent != 0 {
424                    return Err(NumberOutOfScope);
425                }
426
427                TryFrom::try_from(mantissa).map_err(Into::into)
428            }
429        }
430
431        impl_integer!($t);
432    )*)
433}
434
435macro_rules! impl_signed {
436    ($( $t:ty ),*) => ($(
437        impl From<$t> for Number {
438            fn from(num: $t) -> Number {
439                if num < 0 {
440                    Number {
441                        category: NEGATIVE,
442                        exponent: 0,
443                        mantissa: -num as u64,
444                    }
445                } else {
446                    Number {
447                        category: POSITIVE,
448                        exponent: 0,
449                        mantissa: num as u64,
450                    }
451                }
452            }
453        }
454
455        impl TryFrom<Number> for $t {
456            type Error = NumberOutOfScope;
457
458            fn try_from(num: Number) -> Result<Self, Self::Error> {
459                let (positive, mantissa, exponent) = num.as_parts();
460
461                if exponent != 0 {
462                    return Err(NumberOutOfScope);
463                }
464
465                let mantissa = if positive {
466                    mantissa as i64
467                } else {
468                    -(mantissa as i64)
469                };
470
471                TryFrom::try_from(mantissa).map_err(Into::into)
472            }
473        }
474
475        impl_integer!($t);
476    )*)
477}
478
479macro_rules! impl_integer {
480    ($t:ty) => {
481        impl PartialEq<$t> for Number {
482            fn eq(&self, other: &$t) -> bool {
483                *self == Number::from(*other)
484            }
485        }
486
487        impl PartialEq<Number> for $t {
488            fn eq(&self, other: &Number) -> bool {
489                Number::from(*self) == *other
490            }
491        }
492    }
493}
494
495impl_signed!(isize, i8, i16, i32, i64);
496impl_unsigned!(usize, u8, u16, u32, u64);
497
498impl ops::Neg for Number {
499    type Output = Number;
500
501    #[inline]
502    fn neg(self) -> Number {
503        Number {
504            category: self.category ^ POSITIVE,
505            exponent: self.exponent,
506            mantissa: self.mantissa,
507        }
508    }
509}
510
511// Commented out for now - not doing math ops for 0.10.0
512// -----------------------------------------------------
513//
514// impl ops::Mul for Number {
515//     type Output = Number;
516
517//     #[inline]
518//     fn mul(self, other: Number) -> Number {
519//         // If either is a NaN, return a NaN
520//         if (self.category | other.category) & NAN_MASK != 0 {
521//             NAN
522//         } else {
523//             Number {
524//                 // If both signs are the same, xoring will produce 0.
525//                 // If they are different, xoring will produce 1.
526//                 // Xor again with 1 to get a proper proper sign!
527//                 // Xor all the things!                              ^ _ ^
528
529//                 category: self.category ^ other.category ^ POSITIVE,
530//                 exponent: self.exponent + other.exponent,
531//                 mantissa: self.mantissa * other.mantissa,
532//             }
533//         }
534//     }
535// }
536
537// impl ops::MulAssign for Number {
538//     #[inline]
539//     fn mul_assign(&mut self, other: Number) {
540//         *self = *self * other;
541//     }
542// }
543
544#[inline]
545fn decimal_power(mut e: u16) -> u64 {
546    static CACHED: [u64; 20] = [
547        1,
548        10,
549        100,
550        1000,
551        10000,
552        100000,
553        1000000,
554        10000000,
555        100000000,
556        1000000000,
557        10000000000,
558        100000000000,
559        1000000000000,
560        10000000000000,
561        100000000000000,
562        1000000000000000,
563        10000000000000000,
564        100000000000000000,
565        1000000000000000000,
566        10000000000000000000,
567    ];
568
569    if e < 20 {
570        CACHED[e as usize]
571    } else {
572        let mut pow = 1u64;
573        while e >= 20 {
574            pow = pow.saturating_mul(CACHED[(e % 20) as usize]);
575            e /= 20;
576        }
577
578        pow
579    }
580}