serde_json/lexical/
exponent.rs

1// Adapted from https://github.com/Alexhuszagh/rust-lexical.
2
3//! Utilities to calculate exponents.
4
5/// Convert usize into i32 without overflow.
6///
7/// This is needed to ensure when adjusting the exponent relative to
8/// the mantissa we do not overflow for comically-long exponents.
9#[inline]
10fn into_i32(value: usize) -> i32 {
11    if value > i32::MAX as usize {
12        i32::MAX
13    } else {
14        value as i32
15    }
16}
17
18// EXPONENT CALCULATION
19
20// Calculate the scientific notation exponent without overflow.
21//
22// For example, 0.1 would be -1, and 10 would be 1 in base 10.
23#[inline]
24pub(crate) fn scientific_exponent(
25    exponent: i32,
26    integer_digits: usize,
27    fraction_start: usize,
28) -> i32 {
29    if integer_digits == 0 {
30        let fraction_start = into_i32(fraction_start);
31        exponent.saturating_sub(fraction_start).saturating_sub(1)
32    } else {
33        let integer_shift = into_i32(integer_digits - 1);
34        exponent.saturating_add(integer_shift)
35    }
36}
37
38// Calculate the mantissa exponent without overflow.
39//
40// Remove the number of digits that contributed to the mantissa past
41// the dot, and add the number of truncated digits from the mantissa,
42// to calculate the scaling factor for the mantissa from a raw exponent.
43#[inline]
44pub(crate) fn mantissa_exponent(exponent: i32, fraction_digits: usize, truncated: usize) -> i32 {
45    if fraction_digits > truncated {
46        exponent.saturating_sub(into_i32(fraction_digits - truncated))
47    } else {
48        exponent.saturating_add(into_i32(truncated - fraction_digits))
49    }
50}