Coverage Report

Created: 2025-10-10 07:11

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/rust_decimal-1.37.2/src/str.rs
Line
Count
Source
1
use crate::{
2
    constants::{BYTES_TO_OVERFLOW_U64, MAX_SCALE, MAX_STR_BUFFER_SIZE, OVERFLOW_U96, WILL_OVERFLOW_U64},
3
    error::{tail_error, Error},
4
    ops::array::{add_by_internal_flattened, add_one_internal, div_by_u32, is_all_zero, mul_by_u32},
5
    Decimal,
6
};
7
8
use arrayvec::{ArrayString, ArrayVec};
9
10
use alloc::{string::String, vec::Vec};
11
use core::fmt;
12
13
// impl that doesn't allocate for serialization purposes.
14
26.3k
pub(crate) fn to_str_internal(
15
26.3k
    value: &Decimal,
16
26.3k
    append_sign: bool,
17
26.3k
    precision: Option<usize>,
18
26.3k
) -> (ArrayString<MAX_STR_BUFFER_SIZE>, Option<usize>) {
19
    // Get the scale - where we need to put the decimal point
20
26.3k
    let scale = value.scale() as usize;
21
22
    // Convert to a string and manipulate that (neg at front, inject decimal)
23
26.3k
    let mut chars = ArrayVec::<_, MAX_STR_BUFFER_SIZE>::new();
24
26.3k
    let mut working = value.mantissa_array3();
25
171k
    while !is_all_zero(&working) {
26
145k
        let remainder = div_by_u32(&mut working, 10u32);
27
145k
        chars.push(char::from(b'0' + remainder as u8));
28
145k
    }
29
42.4k
    while scale > chars.len() {
30
16.1k
        chars.push('0');
31
16.1k
    }
32
33
26.3k
    let (prec, additional) = match precision {
34
0
        Some(prec) => {
35
0
            let max: usize = MAX_SCALE.into();
36
0
            if prec > max {
37
0
                (max, Some(prec - max))
38
            } else {
39
0
                (prec, None)
40
            }
41
        }
42
26.3k
        None => (scale, None),
43
    };
44
45
26.3k
    let len = chars.len();
46
26.3k
    let whole_len = len - scale;
47
26.3k
    let mut rep = ArrayString::new();
48
    // Append the negative sign if necessary while also keeping track of the length of an "empty" string representation
49
26.3k
    let empty_len = if append_sign && value.is_sign_negative() {
50
0
        rep.push('-');
51
0
        1
52
    } else {
53
26.3k
        0
54
    };
55
161k
    for i in 0..whole_len + prec {
56
161k
        if i == len - scale {
57
3.03k
            if i == 0 {
58
2.11k
                rep.push('0');
59
2.11k
            }
60
3.03k
            rep.push('.');
61
158k
        }
62
63
161k
        if i >= len {
64
0
            rep.push('0');
65
161k
        } else {
66
161k
            let c = chars[len - i - 1];
67
161k
            rep.push(c);
68
161k
        }
69
    }
70
71
    // corner case for when we truncated everything in a low fractional
72
26.3k
    if rep.len() == empty_len {
73
9.03k
        rep.push('0');
74
17.2k
    }
75
76
26.3k
    (rep, additional)
77
26.3k
}
78
79
0
pub(crate) fn fmt_scientific_notation(
80
0
    value: &Decimal,
81
0
    exponent_symbol: &str,
82
0
    f: &mut fmt::Formatter<'_>,
83
0
) -> fmt::Result {
84
    #[cfg(not(feature = "std"))]
85
    use alloc::string::ToString;
86
87
    // Get the scale - this is the e value. With multiples of 10 this may get bigger.
88
0
    let mut exponent = -(value.scale() as isize);
89
90
    // Convert the integral to a string
91
0
    let mut chars = Vec::new();
92
0
    let mut working = value.mantissa_array3();
93
0
    while !is_all_zero(&working) {
94
0
        let remainder = div_by_u32(&mut working, 10u32);
95
0
        chars.push(char::from(b'0' + remainder as u8));
96
0
    }
97
98
    // First of all, apply scientific notation rules. That is:
99
    //  1. If non-zero digit comes first, move decimal point left so that e is a positive integer
100
    //  2. If decimal point comes first, move decimal point right until after the first non-zero digit
101
    // Since decimal notation naturally lends itself this way, we just need to inject the decimal
102
    // point in the right place and adjust the exponent accordingly.
103
104
0
    let len = chars.len();
105
    let mut rep;
106
    // We either are operating with a precision specified, or on defaults. Defaults will perform "smart"
107
    // reduction of precision.
108
0
    if let Some(precision) = f.precision() {
109
0
        if len > 1 {
110
            // If we're zero precision AND it's trailing zeros then strip them
111
0
            if precision == 0 && chars.iter().take(len - 1).all(|c| *c == '0') {
112
0
                rep = chars.iter().skip(len - 1).collect::<String>();
113
0
            } else {
114
                // We may still be zero precision, however we aren't trailing zeros
115
0
                if precision > 0 {
116
0
                    chars.insert(len - 1, '.');
117
0
                }
118
0
                rep = chars
119
0
                    .iter()
120
0
                    .rev()
121
                    // Add on extra zeros according to the precision. At least one, since we added a decimal place.
122
0
                    .chain(core::iter::repeat(&'0'))
123
0
                    .take(if precision == 0 { 1 } else { 2 + precision })
124
0
                    .collect::<String>();
125
            }
126
0
            exponent += (len - 1) as isize;
127
0
        } else if precision > 0 {
128
0
            // We have precision that we want to add
129
0
            chars.push('.');
130
0
            rep = chars
131
0
                .iter()
132
0
                .chain(core::iter::repeat(&'0'))
133
0
                .take(2 + precision)
134
0
                .collect::<String>();
135
0
        } else {
136
0
            rep = chars.iter().collect::<String>();
137
0
        }
138
0
    } else if len > 1 {
139
        // If the number is just trailing zeros then we treat it like 0 precision
140
0
        if chars.iter().take(len - 1).all(|c| *c == '0') {
141
0
            rep = chars.iter().skip(len - 1).collect::<String>();
142
0
        } else {
143
0
            // Otherwise, we need to insert a decimal place and make it a scientific number
144
0
            chars.insert(len - 1, '.');
145
0
            rep = chars.iter().rev().collect::<String>();
146
0
        }
147
0
        exponent += (len - 1) as isize;
148
0
    } else {
149
0
        rep = chars.iter().collect::<String>();
150
0
    }
151
152
0
    rep.push_str(exponent_symbol);
153
0
    rep.push_str(&exponent.to_string());
154
0
    f.pad_integral(value.is_sign_positive(), "", &rep)
155
0
}
156
157
// dedicated implementation for the most common case.
158
#[inline]
159
45.2k
pub(crate) fn parse_str_radix_10(str: &str) -> Result<Decimal, Error> {
160
45.2k
    let bytes = str.as_bytes();
161
45.2k
    if bytes.len() < BYTES_TO_OVERFLOW_U64 {
162
31.7k
        parse_str_radix_10_dispatch::<false, true>(bytes)
163
    } else {
164
13.5k
        parse_str_radix_10_dispatch::<true, true>(bytes)
165
    }
166
45.2k
}
167
168
#[inline]
169
0
pub(crate) fn parse_str_radix_10_exact(str: &str) -> Result<Decimal, Error> {
170
0
    let bytes = str.as_bytes();
171
0
    if bytes.len() < BYTES_TO_OVERFLOW_U64 {
172
0
        parse_str_radix_10_dispatch::<false, false>(bytes)
173
    } else {
174
0
        parse_str_radix_10_dispatch::<true, false>(bytes)
175
    }
176
0
}
177
178
#[inline]
179
45.2k
fn parse_str_radix_10_dispatch<const BIG: bool, const ROUND: bool>(bytes: &[u8]) -> Result<Decimal, Error> {
180
45.2k
    match bytes {
181
45.2k
        [b, rest @ ..] => byte_dispatch_u64::<false, false, false, BIG, true, ROUND>(rest, 0, 0, *b),
182
0
        [] => tail_error("Invalid decimal: empty"),
183
    }
184
45.2k
}
Unexecuted instantiation: rust_decimal::str::parse_str_radix_10_dispatch::<false, false>
rust_decimal::str::parse_str_radix_10_dispatch::<false, true>
Line
Count
Source
179
31.7k
fn parse_str_radix_10_dispatch<const BIG: bool, const ROUND: bool>(bytes: &[u8]) -> Result<Decimal, Error> {
180
31.7k
    match bytes {
181
31.7k
        [b, rest @ ..] => byte_dispatch_u64::<false, false, false, BIG, true, ROUND>(rest, 0, 0, *b),
182
0
        [] => tail_error("Invalid decimal: empty"),
183
    }
184
31.7k
}
rust_decimal::str::parse_str_radix_10_dispatch::<true, true>
Line
Count
Source
179
13.5k
fn parse_str_radix_10_dispatch<const BIG: bool, const ROUND: bool>(bytes: &[u8]) -> Result<Decimal, Error> {
180
13.5k
    match bytes {
181
13.5k
        [b, rest @ ..] => byte_dispatch_u64::<false, false, false, BIG, true, ROUND>(rest, 0, 0, *b),
182
0
        [] => tail_error("Invalid decimal: empty"),
183
    }
184
13.5k
}
Unexecuted instantiation: rust_decimal::str::parse_str_radix_10_dispatch::<true, false>
185
186
#[inline]
187
257k
fn overflow_64(val: u64) -> bool {
188
257k
    val >= WILL_OVERFLOW_U64
189
257k
}
190
191
#[inline]
192
60.6k
pub fn overflow_128(val: u128) -> bool {
193
60.6k
    val >= OVERFLOW_U96
194
60.6k
}
195
196
/// Dispatch the next byte:
197
///
198
/// * POINT - a decimal point has been seen
199
/// * NEG - we've encountered a `-` and the number is negative
200
/// * HAS - a digit has been encountered (when HAS is false it's invalid)
201
/// * BIG - a number that uses 96 bits instead of only 64 bits
202
/// * FIRST - true if it is the first byte in the string
203
#[inline]
204
51.5k
fn dispatch_next<const POINT: bool, const NEG: bool, const HAS: bool, const BIG: bool, const ROUND: bool>(
205
51.5k
    bytes: &[u8],
206
51.5k
    data64: u64,
207
51.5k
    scale: u8,
208
51.5k
) -> Result<Decimal, Error> {
209
51.5k
    if let Some((next, bytes)) = bytes.split_first() {
210
50.9k
        byte_dispatch_u64::<POINT, NEG, HAS, BIG, false, ROUND>(bytes, data64, scale, *next)
211
    } else {
212
618
        handle_data::<NEG, HAS>(data64 as u128, scale)
213
    }
214
51.5k
}
Unexecuted instantiation: rust_decimal::str::dispatch_next::<false, false, false, false, false>
rust_decimal::str::dispatch_next::<false, false, false, false, true>
Line
Count
Source
204
587
fn dispatch_next<const POINT: bool, const NEG: bool, const HAS: bool, const BIG: bool, const ROUND: bool>(
205
587
    bytes: &[u8],
206
587
    data64: u64,
207
587
    scale: u8,
208
587
) -> Result<Decimal, Error> {
209
587
    if let Some((next, bytes)) = bytes.split_first() {
210
587
        byte_dispatch_u64::<POINT, NEG, HAS, BIG, false, ROUND>(bytes, data64, scale, *next)
211
    } else {
212
0
        handle_data::<NEG, HAS>(data64 as u128, scale)
213
    }
214
587
}
rust_decimal::str::dispatch_next::<false, false, false, true, true>
Line
Count
Source
204
54
fn dispatch_next<const POINT: bool, const NEG: bool, const HAS: bool, const BIG: bool, const ROUND: bool>(
205
54
    bytes: &[u8],
206
54
    data64: u64,
207
54
    scale: u8,
208
54
) -> Result<Decimal, Error> {
209
54
    if let Some((next, bytes)) = bytes.split_first() {
210
54
        byte_dispatch_u64::<POINT, NEG, HAS, BIG, false, ROUND>(bytes, data64, scale, *next)
211
    } else {
212
0
        handle_data::<NEG, HAS>(data64 as u128, scale)
213
    }
214
54
}
Unexecuted instantiation: rust_decimal::str::dispatch_next::<false, false, false, true, false>
Unexecuted instantiation: rust_decimal::str::dispatch_next::<false, false, true, false, false>
rust_decimal::str::dispatch_next::<false, false, true, false, true>
Line
Count
Source
204
676
fn dispatch_next<const POINT: bool, const NEG: bool, const HAS: bool, const BIG: bool, const ROUND: bool>(
205
676
    bytes: &[u8],
206
676
    data64: u64,
207
676
    scale: u8,
208
676
) -> Result<Decimal, Error> {
209
676
    if let Some((next, bytes)) = bytes.split_first() {
210
558
        byte_dispatch_u64::<POINT, NEG, HAS, BIG, false, ROUND>(bytes, data64, scale, *next)
211
    } else {
212
118
        handle_data::<NEG, HAS>(data64 as u128, scale)
213
    }
214
676
}
Unexecuted instantiation: rust_decimal::str::dispatch_next::<false, false, true, true, false>
rust_decimal::str::dispatch_next::<false, false, true, true, true>
Line
Count
Source
204
2.50k
fn dispatch_next<const POINT: bool, const NEG: bool, const HAS: bool, const BIG: bool, const ROUND: bool>(
205
2.50k
    bytes: &[u8],
206
2.50k
    data64: u64,
207
2.50k
    scale: u8,
208
2.50k
) -> Result<Decimal, Error> {
209
2.50k
    if let Some((next, bytes)) = bytes.split_first() {
210
2.45k
        byte_dispatch_u64::<POINT, NEG, HAS, BIG, false, ROUND>(bytes, data64, scale, *next)
211
    } else {
212
44
        handle_data::<NEG, HAS>(data64 as u128, scale)
213
    }
214
2.50k
}
Unexecuted instantiation: rust_decimal::str::dispatch_next::<false, true, false, false, false>
rust_decimal::str::dispatch_next::<false, true, false, false, true>
Line
Count
Source
204
18.3k
fn dispatch_next<const POINT: bool, const NEG: bool, const HAS: bool, const BIG: bool, const ROUND: bool>(
205
18.3k
    bytes: &[u8],
206
18.3k
    data64: u64,
207
18.3k
    scale: u8,
208
18.3k
) -> Result<Decimal, Error> {
209
18.3k
    if let Some((next, bytes)) = bytes.split_first() {
210
18.3k
        byte_dispatch_u64::<POINT, NEG, HAS, BIG, false, ROUND>(bytes, data64, scale, *next)
211
    } else {
212
0
        handle_data::<NEG, HAS>(data64 as u128, scale)
213
    }
214
18.3k
}
Unexecuted instantiation: rust_decimal::str::dispatch_next::<false, true, false, true, false>
rust_decimal::str::dispatch_next::<false, true, false, true, true>
Line
Count
Source
204
7.64k
fn dispatch_next<const POINT: bool, const NEG: bool, const HAS: bool, const BIG: bool, const ROUND: bool>(
205
7.64k
    bytes: &[u8],
206
7.64k
    data64: u64,
207
7.64k
    scale: u8,
208
7.64k
) -> Result<Decimal, Error> {
209
7.64k
    if let Some((next, bytes)) = bytes.split_first() {
210
7.64k
        byte_dispatch_u64::<POINT, NEG, HAS, BIG, false, ROUND>(bytes, data64, scale, *next)
211
    } else {
212
0
        handle_data::<NEG, HAS>(data64 as u128, scale)
213
    }
214
7.64k
}
Unexecuted instantiation: rust_decimal::str::dispatch_next::<false, true, true, false, false>
rust_decimal::str::dispatch_next::<false, true, true, false, true>
Line
Count
Source
204
600
fn dispatch_next<const POINT: bool, const NEG: bool, const HAS: bool, const BIG: bool, const ROUND: bool>(
205
600
    bytes: &[u8],
206
600
    data64: u64,
207
600
    scale: u8,
208
600
) -> Result<Decimal, Error> {
209
600
    if let Some((next, bytes)) = bytes.split_first() {
210
484
        byte_dispatch_u64::<POINT, NEG, HAS, BIG, false, ROUND>(bytes, data64, scale, *next)
211
    } else {
212
116
        handle_data::<NEG, HAS>(data64 as u128, scale)
213
    }
214
600
}
Unexecuted instantiation: rust_decimal::str::dispatch_next::<false, true, true, true, false>
rust_decimal::str::dispatch_next::<false, true, true, true, true>
Line
Count
Source
204
1.78k
fn dispatch_next<const POINT: bool, const NEG: bool, const HAS: bool, const BIG: bool, const ROUND: bool>(
205
1.78k
    bytes: &[u8],
206
1.78k
    data64: u64,
207
1.78k
    scale: u8,
208
1.78k
) -> Result<Decimal, Error> {
209
1.78k
    if let Some((next, bytes)) = bytes.split_first() {
210
1.72k
        byte_dispatch_u64::<POINT, NEG, HAS, BIG, false, ROUND>(bytes, data64, scale, *next)
211
    } else {
212
65
        handle_data::<NEG, HAS>(data64 as u128, scale)
213
    }
214
1.78k
}
rust_decimal::str::dispatch_next::<true, true, true, true, true>
Line
Count
Source
204
5.65k
fn dispatch_next<const POINT: bool, const NEG: bool, const HAS: bool, const BIG: bool, const ROUND: bool>(
205
5.65k
    bytes: &[u8],
206
5.65k
    data64: u64,
207
5.65k
    scale: u8,
208
5.65k
) -> Result<Decimal, Error> {
209
5.65k
    if let Some((next, bytes)) = bytes.split_first() {
210
5.58k
        byte_dispatch_u64::<POINT, NEG, HAS, BIG, false, ROUND>(bytes, data64, scale, *next)
211
    } else {
212
63
        handle_data::<NEG, HAS>(data64 as u128, scale)
213
    }
214
5.65k
}
Unexecuted instantiation: rust_decimal::str::dispatch_next::<true, true, true, true, false>
Unexecuted instantiation: rust_decimal::str::dispatch_next::<true, true, true, false, false>
rust_decimal::str::dispatch_next::<true, true, true, false, true>
Line
Count
Source
204
1.55k
fn dispatch_next<const POINT: bool, const NEG: bool, const HAS: bool, const BIG: bool, const ROUND: bool>(
205
1.55k
    bytes: &[u8],
206
1.55k
    data64: u64,
207
1.55k
    scale: u8,
208
1.55k
) -> Result<Decimal, Error> {
209
1.55k
    if let Some((next, bytes)) = bytes.split_first() {
210
1.47k
        byte_dispatch_u64::<POINT, NEG, HAS, BIG, false, ROUND>(bytes, data64, scale, *next)
211
    } else {
212
74
        handle_data::<NEG, HAS>(data64 as u128, scale)
213
    }
214
1.55k
}
Unexecuted instantiation: rust_decimal::str::dispatch_next::<true, true, false, true, true>
Unexecuted instantiation: rust_decimal::str::dispatch_next::<true, true, false, true, false>
Unexecuted instantiation: rust_decimal::str::dispatch_next::<true, true, false, false, true>
Unexecuted instantiation: rust_decimal::str::dispatch_next::<true, true, false, false, false>
rust_decimal::str::dispatch_next::<true, false, true, true, true>
Line
Count
Source
204
8.37k
fn dispatch_next<const POINT: bool, const NEG: bool, const HAS: bool, const BIG: bool, const ROUND: bool>(
205
8.37k
    bytes: &[u8],
206
8.37k
    data64: u64,
207
8.37k
    scale: u8,
208
8.37k
) -> Result<Decimal, Error> {
209
8.37k
    if let Some((next, bytes)) = bytes.split_first() {
210
8.30k
        byte_dispatch_u64::<POINT, NEG, HAS, BIG, false, ROUND>(bytes, data64, scale, *next)
211
    } else {
212
74
        handle_data::<NEG, HAS>(data64 as u128, scale)
213
    }
214
8.37k
}
Unexecuted instantiation: rust_decimal::str::dispatch_next::<true, false, true, true, false>
rust_decimal::str::dispatch_next::<true, false, true, false, true>
Line
Count
Source
204
3.77k
fn dispatch_next<const POINT: bool, const NEG: bool, const HAS: bool, const BIG: bool, const ROUND: bool>(
205
3.77k
    bytes: &[u8],
206
3.77k
    data64: u64,
207
3.77k
    scale: u8,
208
3.77k
) -> Result<Decimal, Error> {
209
3.77k
    if let Some((next, bytes)) = bytes.split_first() {
210
3.71k
        byte_dispatch_u64::<POINT, NEG, HAS, BIG, false, ROUND>(bytes, data64, scale, *next)
211
    } else {
212
64
        handle_data::<NEG, HAS>(data64 as u128, scale)
213
    }
214
3.77k
}
Unexecuted instantiation: rust_decimal::str::dispatch_next::<true, false, true, false, false>
Unexecuted instantiation: rust_decimal::str::dispatch_next::<true, false, false, true, true>
Unexecuted instantiation: rust_decimal::str::dispatch_next::<true, false, false, true, false>
Unexecuted instantiation: rust_decimal::str::dispatch_next::<true, false, false, false, true>
Unexecuted instantiation: rust_decimal::str::dispatch_next::<true, false, false, false, false>
215
216
/// Dispatch the next non-digit byte:
217
///
218
/// * POINT - a decimal point has been seen
219
/// * NEG - we've encountered a `-` and the number is negative
220
/// * HAS - a digit has been encountered (when HAS is false it's invalid)
221
/// * BIG - a number that uses 96 bits instead of only 64 bits
222
/// * FIRST - true if it is the first byte in the string
223
/// * ROUND - attempt to round underflow
224
#[inline(never)]
225
40.6k
fn non_digit_dispatch_u64<
226
40.6k
    const POINT: bool,
227
40.6k
    const NEG: bool,
228
40.6k
    const HAS: bool,
229
40.6k
    const BIG: bool,
230
40.6k
    const FIRST: bool,
231
40.6k
    const ROUND: bool,
232
40.6k
>(
233
40.6k
    bytes: &[u8],
234
40.6k
    data64: u64,
235
40.6k
    scale: u8,
236
40.6k
    b: u8,
237
40.6k
) -> Result<Decimal, Error> {
238
26.0k
    match b {
239
26.0k
        b'-' if FIRST && !HAS => dispatch_next::<false, true, false, BIG, ROUND>(bytes, data64, scale),
240
641
        b'+' if FIRST && !HAS => dispatch_next::<false, false, false, BIG, ROUND>(bytes, data64, scale),
241
14.0k
        b'_' if HAS => handle_separator::<POINT, NEG, BIG, ROUND>(bytes, data64, scale),
242
0
        b => tail_invalid_digit(b),
243
    }
244
40.6k
}
Unexecuted instantiation: rust_decimal::str::non_digit_dispatch_u64::<false, false, false, false, false, false>
Unexecuted instantiation: rust_decimal::str::non_digit_dispatch_u64::<false, false, false, false, false, true>
rust_decimal::str::non_digit_dispatch_u64::<false, false, false, false, true, true>
Line
Count
Source
225
18.9k
fn non_digit_dispatch_u64<
226
18.9k
    const POINT: bool,
227
18.9k
    const NEG: bool,
228
18.9k
    const HAS: bool,
229
18.9k
    const BIG: bool,
230
18.9k
    const FIRST: bool,
231
18.9k
    const ROUND: bool,
232
18.9k
>(
233
18.9k
    bytes: &[u8],
234
18.9k
    data64: u64,
235
18.9k
    scale: u8,
236
18.9k
    b: u8,
237
18.9k
) -> Result<Decimal, Error> {
238
18.3k
    match b {
239
18.3k
        b'-' if FIRST && !HAS => dispatch_next::<false, true, false, BIG, ROUND>(bytes, data64, scale),
240
587
        b'+' if FIRST && !HAS => dispatch_next::<false, false, false, BIG, ROUND>(bytes, data64, scale),
241
0
        b'_' if HAS => handle_separator::<POINT, NEG, BIG, ROUND>(bytes, data64, scale),
242
0
        b => tail_invalid_digit(b),
243
    }
244
18.9k
}
Unexecuted instantiation: rust_decimal::str::non_digit_dispatch_u64::<false, false, false, false, true, false>
rust_decimal::str::non_digit_dispatch_u64::<false, false, false, true, true, true>
Line
Count
Source
225
7.69k
fn non_digit_dispatch_u64<
226
7.69k
    const POINT: bool,
227
7.69k
    const NEG: bool,
228
7.69k
    const HAS: bool,
229
7.69k
    const BIG: bool,
230
7.69k
    const FIRST: bool,
231
7.69k
    const ROUND: bool,
232
7.69k
>(
233
7.69k
    bytes: &[u8],
234
7.69k
    data64: u64,
235
7.69k
    scale: u8,
236
7.69k
    b: u8,
237
7.69k
) -> Result<Decimal, Error> {
238
7.64k
    match b {
239
7.64k
        b'-' if FIRST && !HAS => dispatch_next::<false, true, false, BIG, ROUND>(bytes, data64, scale),
240
54
        b'+' if FIRST && !HAS => dispatch_next::<false, false, false, BIG, ROUND>(bytes, data64, scale),
241
0
        b'_' if HAS => handle_separator::<POINT, NEG, BIG, ROUND>(bytes, data64, scale),
242
0
        b => tail_invalid_digit(b),
243
    }
244
7.69k
}
Unexecuted instantiation: rust_decimal::str::non_digit_dispatch_u64::<false, false, false, true, true, false>
Unexecuted instantiation: rust_decimal::str::non_digit_dispatch_u64::<false, false, false, true, false, true>
Unexecuted instantiation: rust_decimal::str::non_digit_dispatch_u64::<false, false, false, true, false, false>
rust_decimal::str::non_digit_dispatch_u64::<false, false, true, true, false, true>
Line
Count
Source
225
2.50k
fn non_digit_dispatch_u64<
226
2.50k
    const POINT: bool,
227
2.50k
    const NEG: bool,
228
2.50k
    const HAS: bool,
229
2.50k
    const BIG: bool,
230
2.50k
    const FIRST: bool,
231
2.50k
    const ROUND: bool,
232
2.50k
>(
233
2.50k
    bytes: &[u8],
234
2.50k
    data64: u64,
235
2.50k
    scale: u8,
236
2.50k
    b: u8,
237
2.50k
) -> Result<Decimal, Error> {
238
0
    match b {
239
0
        b'-' if FIRST && !HAS => dispatch_next::<false, true, false, BIG, ROUND>(bytes, data64, scale),
240
0
        b'+' if FIRST && !HAS => dispatch_next::<false, false, false, BIG, ROUND>(bytes, data64, scale),
241
2.50k
        b'_' if HAS => handle_separator::<POINT, NEG, BIG, ROUND>(bytes, data64, scale),
242
0
        b => tail_invalid_digit(b),
243
    }
244
2.50k
}
Unexecuted instantiation: rust_decimal::str::non_digit_dispatch_u64::<false, false, true, true, false, false>
rust_decimal::str::non_digit_dispatch_u64::<false, false, true, false, false, true>
Line
Count
Source
225
676
fn non_digit_dispatch_u64<
226
676
    const POINT: bool,
227
676
    const NEG: bool,
228
676
    const HAS: bool,
229
676
    const BIG: bool,
230
676
    const FIRST: bool,
231
676
    const ROUND: bool,
232
676
>(
233
676
    bytes: &[u8],
234
676
    data64: u64,
235
676
    scale: u8,
236
676
    b: u8,
237
676
) -> Result<Decimal, Error> {
238
0
    match b {
239
0
        b'-' if FIRST && !HAS => dispatch_next::<false, true, false, BIG, ROUND>(bytes, data64, scale),
240
0
        b'+' if FIRST && !HAS => dispatch_next::<false, false, false, BIG, ROUND>(bytes, data64, scale),
241
676
        b'_' if HAS => handle_separator::<POINT, NEG, BIG, ROUND>(bytes, data64, scale),
242
0
        b => tail_invalid_digit(b),
243
    }
244
676
}
Unexecuted instantiation: rust_decimal::str::non_digit_dispatch_u64::<false, false, true, false, false, false>
rust_decimal::str::non_digit_dispatch_u64::<false, true, true, true, false, true>
Line
Count
Source
225
1.78k
fn non_digit_dispatch_u64<
226
1.78k
    const POINT: bool,
227
1.78k
    const NEG: bool,
228
1.78k
    const HAS: bool,
229
1.78k
    const BIG: bool,
230
1.78k
    const FIRST: bool,
231
1.78k
    const ROUND: bool,
232
1.78k
>(
233
1.78k
    bytes: &[u8],
234
1.78k
    data64: u64,
235
1.78k
    scale: u8,
236
1.78k
    b: u8,
237
1.78k
) -> Result<Decimal, Error> {
238
0
    match b {
239
0
        b'-' if FIRST && !HAS => dispatch_next::<false, true, false, BIG, ROUND>(bytes, data64, scale),
240
0
        b'+' if FIRST && !HAS => dispatch_next::<false, false, false, BIG, ROUND>(bytes, data64, scale),
241
1.78k
        b'_' if HAS => handle_separator::<POINT, NEG, BIG, ROUND>(bytes, data64, scale),
242
0
        b => tail_invalid_digit(b),
243
    }
244
1.78k
}
Unexecuted instantiation: rust_decimal::str::non_digit_dispatch_u64::<false, true, true, true, false, false>
rust_decimal::str::non_digit_dispatch_u64::<false, true, true, false, false, true>
Line
Count
Source
225
600
fn non_digit_dispatch_u64<
226
600
    const POINT: bool,
227
600
    const NEG: bool,
228
600
    const HAS: bool,
229
600
    const BIG: bool,
230
600
    const FIRST: bool,
231
600
    const ROUND: bool,
232
600
>(
233
600
    bytes: &[u8],
234
600
    data64: u64,
235
600
    scale: u8,
236
600
    b: u8,
237
600
) -> Result<Decimal, Error> {
238
0
    match b {
239
0
        b'-' if FIRST && !HAS => dispatch_next::<false, true, false, BIG, ROUND>(bytes, data64, scale),
240
0
        b'+' if FIRST && !HAS => dispatch_next::<false, false, false, BIG, ROUND>(bytes, data64, scale),
241
600
        b'_' if HAS => handle_separator::<POINT, NEG, BIG, ROUND>(bytes, data64, scale),
242
0
        b => tail_invalid_digit(b),
243
    }
244
600
}
Unexecuted instantiation: rust_decimal::str::non_digit_dispatch_u64::<false, true, true, false, false, false>
Unexecuted instantiation: rust_decimal::str::non_digit_dispatch_u64::<false, true, false, true, false, true>
Unexecuted instantiation: rust_decimal::str::non_digit_dispatch_u64::<false, true, false, true, false, false>
Unexecuted instantiation: rust_decimal::str::non_digit_dispatch_u64::<false, true, false, false, false, true>
Unexecuted instantiation: rust_decimal::str::non_digit_dispatch_u64::<false, true, false, false, false, false>
Unexecuted instantiation: rust_decimal::str::non_digit_dispatch_u64::<true, true, true, true, false, false>
rust_decimal::str::non_digit_dispatch_u64::<true, true, true, true, false, true>
Line
Count
Source
225
2.74k
fn non_digit_dispatch_u64<
226
2.74k
    const POINT: bool,
227
2.74k
    const NEG: bool,
228
2.74k
    const HAS: bool,
229
2.74k
    const BIG: bool,
230
2.74k
    const FIRST: bool,
231
2.74k
    const ROUND: bool,
232
2.74k
>(
233
2.74k
    bytes: &[u8],
234
2.74k
    data64: u64,
235
2.74k
    scale: u8,
236
2.74k
    b: u8,
237
2.74k
) -> Result<Decimal, Error> {
238
0
    match b {
239
0
        b'-' if FIRST && !HAS => dispatch_next::<false, true, false, BIG, ROUND>(bytes, data64, scale),
240
0
        b'+' if FIRST && !HAS => dispatch_next::<false, false, false, BIG, ROUND>(bytes, data64, scale),
241
2.74k
        b'_' if HAS => handle_separator::<POINT, NEG, BIG, ROUND>(bytes, data64, scale),
242
0
        b => tail_invalid_digit(b),
243
    }
244
2.74k
}
Unexecuted instantiation: rust_decimal::str::non_digit_dispatch_u64::<true, true, true, false, false, false>
rust_decimal::str::non_digit_dispatch_u64::<true, true, true, false, false, true>
Line
Count
Source
225
239
fn non_digit_dispatch_u64<
226
239
    const POINT: bool,
227
239
    const NEG: bool,
228
239
    const HAS: bool,
229
239
    const BIG: bool,
230
239
    const FIRST: bool,
231
239
    const ROUND: bool,
232
239
>(
233
239
    bytes: &[u8],
234
239
    data64: u64,
235
239
    scale: u8,
236
239
    b: u8,
237
239
) -> Result<Decimal, Error> {
238
0
    match b {
239
0
        b'-' if FIRST && !HAS => dispatch_next::<false, true, false, BIG, ROUND>(bytes, data64, scale),
240
0
        b'+' if FIRST && !HAS => dispatch_next::<false, false, false, BIG, ROUND>(bytes, data64, scale),
241
239
        b'_' if HAS => handle_separator::<POINT, NEG, BIG, ROUND>(bytes, data64, scale),
242
0
        b => tail_invalid_digit(b),
243
    }
244
239
}
Unexecuted instantiation: rust_decimal::str::non_digit_dispatch_u64::<true, true, false, false, false, false>
Unexecuted instantiation: rust_decimal::str::non_digit_dispatch_u64::<true, true, false, false, false, true>
Unexecuted instantiation: rust_decimal::str::non_digit_dispatch_u64::<true, true, false, true, false, false>
Unexecuted instantiation: rust_decimal::str::non_digit_dispatch_u64::<true, true, false, true, false, true>
Unexecuted instantiation: rust_decimal::str::non_digit_dispatch_u64::<true, false, false, false, false, false>
Unexecuted instantiation: rust_decimal::str::non_digit_dispatch_u64::<true, false, false, false, false, true>
Unexecuted instantiation: rust_decimal::str::non_digit_dispatch_u64::<true, false, false, true, false, false>
Unexecuted instantiation: rust_decimal::str::non_digit_dispatch_u64::<true, false, false, true, false, true>
Unexecuted instantiation: rust_decimal::str::non_digit_dispatch_u64::<true, false, true, false, false, false>
rust_decimal::str::non_digit_dispatch_u64::<true, false, true, false, false, true>
Line
Count
Source
225
481
fn non_digit_dispatch_u64<
226
481
    const POINT: bool,
227
481
    const NEG: bool,
228
481
    const HAS: bool,
229
481
    const BIG: bool,
230
481
    const FIRST: bool,
231
481
    const ROUND: bool,
232
481
>(
233
481
    bytes: &[u8],
234
481
    data64: u64,
235
481
    scale: u8,
236
481
    b: u8,
237
481
) -> Result<Decimal, Error> {
238
0
    match b {
239
0
        b'-' if FIRST && !HAS => dispatch_next::<false, true, false, BIG, ROUND>(bytes, data64, scale),
240
0
        b'+' if FIRST && !HAS => dispatch_next::<false, false, false, BIG, ROUND>(bytes, data64, scale),
241
481
        b'_' if HAS => handle_separator::<POINT, NEG, BIG, ROUND>(bytes, data64, scale),
242
0
        b => tail_invalid_digit(b),
243
    }
244
481
}
Unexecuted instantiation: rust_decimal::str::non_digit_dispatch_u64::<true, false, true, true, false, false>
rust_decimal::str::non_digit_dispatch_u64::<true, false, true, true, false, true>
Line
Count
Source
225
4.97k
fn non_digit_dispatch_u64<
226
4.97k
    const POINT: bool,
227
4.97k
    const NEG: bool,
228
4.97k
    const HAS: bool,
229
4.97k
    const BIG: bool,
230
4.97k
    const FIRST: bool,
231
4.97k
    const ROUND: bool,
232
4.97k
>(
233
4.97k
    bytes: &[u8],
234
4.97k
    data64: u64,
235
4.97k
    scale: u8,
236
4.97k
    b: u8,
237
4.97k
) -> Result<Decimal, Error> {
238
0
    match b {
239
0
        b'-' if FIRST && !HAS => dispatch_next::<false, true, false, BIG, ROUND>(bytes, data64, scale),
240
0
        b'+' if FIRST && !HAS => dispatch_next::<false, false, false, BIG, ROUND>(bytes, data64, scale),
241
4.97k
        b'_' if HAS => handle_separator::<POINT, NEG, BIG, ROUND>(bytes, data64, scale),
242
0
        b => tail_invalid_digit(b),
243
    }
244
4.97k
}
245
246
#[inline]
247
414k
fn byte_dispatch_u64<
248
414k
    const POINT: bool,
249
414k
    const NEG: bool,
250
414k
    const HAS: bool,
251
414k
    const BIG: bool,
252
414k
    const FIRST: bool,
253
414k
    const ROUND: bool,
254
414k
>(
255
414k
    bytes: &[u8],
256
414k
    data64: u64,
257
414k
    scale: u8,
258
414k
    b: u8,
259
414k
) -> Result<Decimal, Error> {
260
10.9k
    match b {
261
376k
        b'0'..=b'9' => handle_digit_64::<POINT, NEG, BIG, ROUND>(bytes, data64, scale, b - b'0'),
262
10.9k
        b'.' if !POINT => handle_point::<NEG, HAS, BIG, ROUND>(bytes, data64, scale),
263
40.6k
        b => non_digit_dispatch_u64::<POINT, NEG, HAS, BIG, FIRST, ROUND>(bytes, data64, scale, b),
264
    }
265
414k
}
Unexecuted instantiation: rust_decimal::str::byte_dispatch_u64::<false, false, false, false, false, false>
rust_decimal::str::byte_dispatch_u64::<false, false, false, false, false, true>
Line
Count
Source
247
587
fn byte_dispatch_u64<
248
587
    const POINT: bool,
249
587
    const NEG: bool,
250
587
    const HAS: bool,
251
587
    const BIG: bool,
252
587
    const FIRST: bool,
253
587
    const ROUND: bool,
254
587
>(
255
587
    bytes: &[u8],
256
587
    data64: u64,
257
587
    scale: u8,
258
587
    b: u8,
259
587
) -> Result<Decimal, Error> {
260
0
    match b {
261
587
        b'0'..=b'9' => handle_digit_64::<POINT, NEG, BIG, ROUND>(bytes, data64, scale, b - b'0'),
262
0
        b'.' if !POINT => handle_point::<NEG, HAS, BIG, ROUND>(bytes, data64, scale),
263
0
        b => non_digit_dispatch_u64::<POINT, NEG, HAS, BIG, FIRST, ROUND>(bytes, data64, scale, b),
264
    }
265
587
}
rust_decimal::str::byte_dispatch_u64::<false, false, false, false, true, true>
Line
Count
Source
247
31.7k
fn byte_dispatch_u64<
248
31.7k
    const POINT: bool,
249
31.7k
    const NEG: bool,
250
31.7k
    const HAS: bool,
251
31.7k
    const BIG: bool,
252
31.7k
    const FIRST: bool,
253
31.7k
    const ROUND: bool,
254
31.7k
>(
255
31.7k
    bytes: &[u8],
256
31.7k
    data64: u64,
257
31.7k
    scale: u8,
258
31.7k
    b: u8,
259
31.7k
) -> Result<Decimal, Error> {
260
0
    match b {
261
12.7k
        b'0'..=b'9' => handle_digit_64::<POINT, NEG, BIG, ROUND>(bytes, data64, scale, b - b'0'),
262
0
        b'.' if !POINT => handle_point::<NEG, HAS, BIG, ROUND>(bytes, data64, scale),
263
18.9k
        b => non_digit_dispatch_u64::<POINT, NEG, HAS, BIG, FIRST, ROUND>(bytes, data64, scale, b),
264
    }
265
31.7k
}
Unexecuted instantiation: rust_decimal::str::byte_dispatch_u64::<false, false, false, false, true, false>
rust_decimal::str::byte_dispatch_u64::<false, false, false, true, true, true>
Line
Count
Source
247
13.5k
fn byte_dispatch_u64<
248
13.5k
    const POINT: bool,
249
13.5k
    const NEG: bool,
250
13.5k
    const HAS: bool,
251
13.5k
    const BIG: bool,
252
13.5k
    const FIRST: bool,
253
13.5k
    const ROUND: bool,
254
13.5k
>(
255
13.5k
    bytes: &[u8],
256
13.5k
    data64: u64,
257
13.5k
    scale: u8,
258
13.5k
    b: u8,
259
13.5k
) -> Result<Decimal, Error> {
260
0
    match b {
261
5.87k
        b'0'..=b'9' => handle_digit_64::<POINT, NEG, BIG, ROUND>(bytes, data64, scale, b - b'0'),
262
0
        b'.' if !POINT => handle_point::<NEG, HAS, BIG, ROUND>(bytes, data64, scale),
263
7.69k
        b => non_digit_dispatch_u64::<POINT, NEG, HAS, BIG, FIRST, ROUND>(bytes, data64, scale, b),
264
    }
265
13.5k
}
Unexecuted instantiation: rust_decimal::str::byte_dispatch_u64::<false, false, false, true, true, false>
rust_decimal::str::byte_dispatch_u64::<false, false, false, true, false, true>
Line
Count
Source
247
54
fn byte_dispatch_u64<
248
54
    const POINT: bool,
249
54
    const NEG: bool,
250
54
    const HAS: bool,
251
54
    const BIG: bool,
252
54
    const FIRST: bool,
253
54
    const ROUND: bool,
254
54
>(
255
54
    bytes: &[u8],
256
54
    data64: u64,
257
54
    scale: u8,
258
54
    b: u8,
259
54
) -> Result<Decimal, Error> {
260
0
    match b {
261
54
        b'0'..=b'9' => handle_digit_64::<POINT, NEG, BIG, ROUND>(bytes, data64, scale, b - b'0'),
262
0
        b'.' if !POINT => handle_point::<NEG, HAS, BIG, ROUND>(bytes, data64, scale),
263
0
        b => non_digit_dispatch_u64::<POINT, NEG, HAS, BIG, FIRST, ROUND>(bytes, data64, scale, b),
264
    }
265
54
}
Unexecuted instantiation: rust_decimal::str::byte_dispatch_u64::<false, false, false, true, false, false>
rust_decimal::str::byte_dispatch_u64::<false, false, true, true, false, true>
Line
Count
Source
247
65.4k
fn byte_dispatch_u64<
248
65.4k
    const POINT: bool,
249
65.4k
    const NEG: bool,
250
65.4k
    const HAS: bool,
251
65.4k
    const BIG: bool,
252
65.4k
    const FIRST: bool,
253
65.4k
    const ROUND: bool,
254
65.4k
>(
255
65.4k
    bytes: &[u8],
256
65.4k
    data64: u64,
257
65.4k
    scale: u8,
258
65.4k
    b: u8,
259
65.4k
) -> Result<Decimal, Error> {
260
3.39k
    match b {
261
62.0k
        b'0'..=b'9' => handle_digit_64::<POINT, NEG, BIG, ROUND>(bytes, data64, scale, b - b'0'),
262
3.39k
        b'.' if !POINT => handle_point::<NEG, HAS, BIG, ROUND>(bytes, data64, scale),
263
2.50k
        b => non_digit_dispatch_u64::<POINT, NEG, HAS, BIG, FIRST, ROUND>(bytes, data64, scale, b),
264
    }
265
65.4k
}
Unexecuted instantiation: rust_decimal::str::byte_dispatch_u64::<false, false, true, true, false, false>
rust_decimal::str::byte_dispatch_u64::<false, false, true, false, false, true>
Line
Count
Source
247
34.5k
fn byte_dispatch_u64<
248
34.5k
    const POINT: bool,
249
34.5k
    const NEG: bool,
250
34.5k
    const HAS: bool,
251
34.5k
    const BIG: bool,
252
34.5k
    const FIRST: bool,
253
34.5k
    const ROUND: bool,
254
34.5k
>(
255
34.5k
    bytes: &[u8],
256
34.5k
    data64: u64,
257
34.5k
    scale: u8,
258
34.5k
    b: u8,
259
34.5k
) -> Result<Decimal, Error> {
260
3.29k
    match b {
261
31.3k
        b'0'..=b'9' => handle_digit_64::<POINT, NEG, BIG, ROUND>(bytes, data64, scale, b - b'0'),
262
3.29k
        b'.' if !POINT => handle_point::<NEG, HAS, BIG, ROUND>(bytes, data64, scale),
263
676
        b => non_digit_dispatch_u64::<POINT, NEG, HAS, BIG, FIRST, ROUND>(bytes, data64, scale, b),
264
    }
265
34.5k
}
Unexecuted instantiation: rust_decimal::str::byte_dispatch_u64::<false, false, true, false, false, false>
Unexecuted instantiation: rust_decimal::str::byte_dispatch_u64::<false, true, false, false, false, false>
rust_decimal::str::byte_dispatch_u64::<false, true, false, false, false, true>
Line
Count
Source
247
18.3k
fn byte_dispatch_u64<
248
18.3k
    const POINT: bool,
249
18.3k
    const NEG: bool,
250
18.3k
    const HAS: bool,
251
18.3k
    const BIG: bool,
252
18.3k
    const FIRST: bool,
253
18.3k
    const ROUND: bool,
254
18.3k
>(
255
18.3k
    bytes: &[u8],
256
18.3k
    data64: u64,
257
18.3k
    scale: u8,
258
18.3k
    b: u8,
259
18.3k
) -> Result<Decimal, Error> {
260
0
    match b {
261
18.3k
        b'0'..=b'9' => handle_digit_64::<POINT, NEG, BIG, ROUND>(bytes, data64, scale, b - b'0'),
262
0
        b'.' if !POINT => handle_point::<NEG, HAS, BIG, ROUND>(bytes, data64, scale),
263
0
        b => non_digit_dispatch_u64::<POINT, NEG, HAS, BIG, FIRST, ROUND>(bytes, data64, scale, b),
264
    }
265
18.3k
}
Unexecuted instantiation: rust_decimal::str::byte_dispatch_u64::<false, true, false, true, false, false>
rust_decimal::str::byte_dispatch_u64::<false, true, false, true, false, true>
Line
Count
Source
247
7.64k
fn byte_dispatch_u64<
248
7.64k
    const POINT: bool,
249
7.64k
    const NEG: bool,
250
7.64k
    const HAS: bool,
251
7.64k
    const BIG: bool,
252
7.64k
    const FIRST: bool,
253
7.64k
    const ROUND: bool,
254
7.64k
>(
255
7.64k
    bytes: &[u8],
256
7.64k
    data64: u64,
257
7.64k
    scale: u8,
258
7.64k
    b: u8,
259
7.64k
) -> Result<Decimal, Error> {
260
0
    match b {
261
7.64k
        b'0'..=b'9' => handle_digit_64::<POINT, NEG, BIG, ROUND>(bytes, data64, scale, b - b'0'),
262
0
        b'.' if !POINT => handle_point::<NEG, HAS, BIG, ROUND>(bytes, data64, scale),
263
0
        b => non_digit_dispatch_u64::<POINT, NEG, HAS, BIG, FIRST, ROUND>(bytes, data64, scale, b),
264
    }
265
7.64k
}
Unexecuted instantiation: rust_decimal::str::byte_dispatch_u64::<false, true, true, false, false, false>
rust_decimal::str::byte_dispatch_u64::<false, true, true, false, false, true>
Line
Count
Source
247
15.2k
fn byte_dispatch_u64<
248
15.2k
    const POINT: bool,
249
15.2k
    const NEG: bool,
250
15.2k
    const HAS: bool,
251
15.2k
    const BIG: bool,
252
15.2k
    const FIRST: bool,
253
15.2k
    const ROUND: bool,
254
15.2k
>(
255
15.2k
    bytes: &[u8],
256
15.2k
    data64: u64,
257
15.2k
    scale: u8,
258
15.2k
    b: u8,
259
15.2k
) -> Result<Decimal, Error> {
260
1.31k
    match b {
261
13.9k
        b'0'..=b'9' => handle_digit_64::<POINT, NEG, BIG, ROUND>(bytes, data64, scale, b - b'0'),
262
1.31k
        b'.' if !POINT => handle_point::<NEG, HAS, BIG, ROUND>(bytes, data64, scale),
263
600
        b => non_digit_dispatch_u64::<POINT, NEG, HAS, BIG, FIRST, ROUND>(bytes, data64, scale, b),
264
    }
265
15.2k
}
Unexecuted instantiation: rust_decimal::str::byte_dispatch_u64::<false, true, true, true, false, false>
rust_decimal::str::byte_dispatch_u64::<false, true, true, true, false, true>
Line
Count
Source
247
96.3k
fn byte_dispatch_u64<
248
96.3k
    const POINT: bool,
249
96.3k
    const NEG: bool,
250
96.3k
    const HAS: bool,
251
96.3k
    const BIG: bool,
252
96.3k
    const FIRST: bool,
253
96.3k
    const ROUND: bool,
254
96.3k
>(
255
96.3k
    bytes: &[u8],
256
96.3k
    data64: u64,
257
96.3k
    scale: u8,
258
96.3k
    b: u8,
259
96.3k
) -> Result<Decimal, Error> {
260
2.90k
    match b {
261
93.4k
        b'0'..=b'9' => handle_digit_64::<POINT, NEG, BIG, ROUND>(bytes, data64, scale, b - b'0'),
262
2.90k
        b'.' if !POINT => handle_point::<NEG, HAS, BIG, ROUND>(bytes, data64, scale),
263
1.78k
        b => non_digit_dispatch_u64::<POINT, NEG, HAS, BIG, FIRST, ROUND>(bytes, data64, scale, b),
264
    }
265
96.3k
}
Unexecuted instantiation: rust_decimal::str::byte_dispatch_u64::<true, true, true, true, false, false>
rust_decimal::str::byte_dispatch_u64::<true, true, true, true, false, true>
Line
Count
Source
247
49.7k
fn byte_dispatch_u64<
248
49.7k
    const POINT: bool,
249
49.7k
    const NEG: bool,
250
49.7k
    const HAS: bool,
251
49.7k
    const BIG: bool,
252
49.7k
    const FIRST: bool,
253
49.7k
    const ROUND: bool,
254
49.7k
>(
255
49.7k
    bytes: &[u8],
256
49.7k
    data64: u64,
257
49.7k
    scale: u8,
258
49.7k
    b: u8,
259
49.7k
) -> Result<Decimal, Error> {
260
0
    match b {
261
49.7k
        b'0'..=b'9' => handle_digit_64::<POINT, NEG, BIG, ROUND>(bytes, data64, scale, b - b'0'),
262
0
        b'.' if !POINT => handle_point::<NEG, HAS, BIG, ROUND>(bytes, data64, scale),
263
2.74k
        b => non_digit_dispatch_u64::<POINT, NEG, HAS, BIG, FIRST, ROUND>(bytes, data64, scale, b),
264
    }
265
49.7k
}
Unexecuted instantiation: rust_decimal::str::byte_dispatch_u64::<true, true, true, false, false, false>
rust_decimal::str::byte_dispatch_u64::<true, true, true, false, false, true>
Line
Count
Source
247
4.11k
fn byte_dispatch_u64<
248
4.11k
    const POINT: bool,
249
4.11k
    const NEG: bool,
250
4.11k
    const HAS: bool,
251
4.11k
    const BIG: bool,
252
4.11k
    const FIRST: bool,
253
4.11k
    const ROUND: bool,
254
4.11k
>(
255
4.11k
    bytes: &[u8],
256
4.11k
    data64: u64,
257
4.11k
    scale: u8,
258
4.11k
    b: u8,
259
4.11k
) -> Result<Decimal, Error> {
260
0
    match b {
261
4.11k
        b'0'..=b'9' => handle_digit_64::<POINT, NEG, BIG, ROUND>(bytes, data64, scale, b - b'0'),
262
0
        b'.' if !POINT => handle_point::<NEG, HAS, BIG, ROUND>(bytes, data64, scale),
263
239
        b => non_digit_dispatch_u64::<POINT, NEG, HAS, BIG, FIRST, ROUND>(bytes, data64, scale, b),
264
    }
265
4.11k
}
Unexecuted instantiation: rust_decimal::str::byte_dispatch_u64::<true, true, false, false, false, false>
Unexecuted instantiation: rust_decimal::str::byte_dispatch_u64::<true, true, false, false, false, true>
Unexecuted instantiation: rust_decimal::str::byte_dispatch_u64::<true, true, false, true, false, false>
Unexecuted instantiation: rust_decimal::str::byte_dispatch_u64::<true, true, false, true, false, true>
rust_decimal::str::byte_dispatch_u64::<true, false, true, true, false, true>
Line
Count
Source
247
53.6k
fn byte_dispatch_u64<
248
53.6k
    const POINT: bool,
249
53.6k
    const NEG: bool,
250
53.6k
    const HAS: bool,
251
53.6k
    const BIG: bool,
252
53.6k
    const FIRST: bool,
253
53.6k
    const ROUND: bool,
254
53.6k
>(
255
53.6k
    bytes: &[u8],
256
53.6k
    data64: u64,
257
53.6k
    scale: u8,
258
53.6k
    b: u8,
259
53.6k
) -> Result<Decimal, Error> {
260
0
    match b {
261
53.6k
        b'0'..=b'9' => handle_digit_64::<POINT, NEG, BIG, ROUND>(bytes, data64, scale, b - b'0'),
262
0
        b'.' if !POINT => handle_point::<NEG, HAS, BIG, ROUND>(bytes, data64, scale),
263
4.97k
        b => non_digit_dispatch_u64::<POINT, NEG, HAS, BIG, FIRST, ROUND>(bytes, data64, scale, b),
264
    }
265
53.6k
}
Unexecuted instantiation: rust_decimal::str::byte_dispatch_u64::<true, false, true, true, false, false>
rust_decimal::str::byte_dispatch_u64::<true, false, true, false, false, true>
Line
Count
Source
247
22.8k
fn byte_dispatch_u64<
248
22.8k
    const POINT: bool,
249
22.8k
    const NEG: bool,
250
22.8k
    const HAS: bool,
251
22.8k
    const BIG: bool,
252
22.8k
    const FIRST: bool,
253
22.8k
    const ROUND: bool,
254
22.8k
>(
255
22.8k
    bytes: &[u8],
256
22.8k
    data64: u64,
257
22.8k
    scale: u8,
258
22.8k
    b: u8,
259
22.8k
) -> Result<Decimal, Error> {
260
0
    match b {
261
22.8k
        b'0'..=b'9' => handle_digit_64::<POINT, NEG, BIG, ROUND>(bytes, data64, scale, b - b'0'),
262
0
        b'.' if !POINT => handle_point::<NEG, HAS, BIG, ROUND>(bytes, data64, scale),
263
481
        b => non_digit_dispatch_u64::<POINT, NEG, HAS, BIG, FIRST, ROUND>(bytes, data64, scale, b),
264
    }
265
22.8k
}
Unexecuted instantiation: rust_decimal::str::byte_dispatch_u64::<true, false, true, false, false, false>
Unexecuted instantiation: rust_decimal::str::byte_dispatch_u64::<true, false, false, true, false, true>
Unexecuted instantiation: rust_decimal::str::byte_dispatch_u64::<true, false, false, true, false, false>
Unexecuted instantiation: rust_decimal::str::byte_dispatch_u64::<true, false, false, false, false, true>
Unexecuted instantiation: rust_decimal::str::byte_dispatch_u64::<true, false, false, false, false, false>
266
267
#[inline(never)]
268
362k
fn handle_digit_64<const POINT: bool, const NEG: bool, const BIG: bool, const ROUND: bool>(
269
362k
    bytes: &[u8],
270
362k
    data64: u64,
271
362k
    scale: u8,
272
362k
    digit: u8,
273
362k
) -> Result<Decimal, Error> {
274
    // we have already validated that we cannot overflow
275
362k
    let data64 = data64 * 10 + digit as u64;
276
362k
    let scale = if POINT { scale + 1 } else { 0 };
277
278
362k
    if let Some((next, bytes)) = bytes.split_first() {
279
328k
        let next = *next;
280
328k
        if POINT && BIG && scale >= 28 {
281
332
            if ROUND {
282
332
                maybe_round(data64 as u128, next, scale, POINT, NEG)
283
            } else {
284
0
                Err(Error::Underflow)
285
            }
286
328k
        } else if BIG && overflow_64(data64) {
287
10.4k
            handle_full_128::<POINT, NEG, ROUND>(data64 as u128, bytes, scale, next)
288
        } else {
289
317k
            byte_dispatch_u64::<POINT, NEG, true, BIG, false, ROUND>(bytes, data64, scale, next)
290
        }
291
    } else {
292
33.8k
        let data: u128 = data64 as u128;
293
294
33.8k
        handle_data::<NEG, true>(data, scale)
295
    }
296
362k
}
Unexecuted instantiation: rust_decimal::str::handle_digit_64::<false, false, false, false>
rust_decimal::str::handle_digit_64::<false, false, false, true>
Line
Count
Source
268
43.9k
fn handle_digit_64<const POINT: bool, const NEG: bool, const BIG: bool, const ROUND: bool>(
269
43.9k
    bytes: &[u8],
270
43.9k
    data64: u64,
271
43.9k
    scale: u8,
272
43.9k
    digit: u8,
273
43.9k
) -> Result<Decimal, Error> {
274
    // we have already validated that we cannot overflow
275
43.9k
    let data64 = data64 * 10 + digit as u64;
276
43.9k
    let scale = if POINT { scale + 1 } else { 0 };
277
278
43.9k
    if let Some((next, bytes)) = bytes.split_first() {
279
34.0k
        let next = *next;
280
34.0k
        if POINT && BIG && scale >= 28 {
281
0
            if ROUND {
282
0
                maybe_round(data64 as u128, next, scale, POINT, NEG)
283
            } else {
284
0
                Err(Error::Underflow)
285
            }
286
34.0k
        } else if BIG && overflow_64(data64) {
287
0
            handle_full_128::<POINT, NEG, ROUND>(data64 as u128, bytes, scale, next)
288
        } else {
289
34.0k
            byte_dispatch_u64::<POINT, NEG, true, BIG, false, ROUND>(bytes, data64, scale, next)
290
        }
291
    } else {
292
9.94k
        let data: u128 = data64 as u128;
293
294
9.94k
        handle_data::<NEG, true>(data, scale)
295
    }
296
43.9k
}
rust_decimal::str::handle_digit_64::<false, false, true, true>
Line
Count
Source
268
65.5k
fn handle_digit_64<const POINT: bool, const NEG: bool, const BIG: bool, const ROUND: bool>(
269
65.5k
    bytes: &[u8],
270
65.5k
    data64: u64,
271
65.5k
    scale: u8,
272
65.5k
    digit: u8,
273
65.5k
) -> Result<Decimal, Error> {
274
    // we have already validated that we cannot overflow
275
65.5k
    let data64 = data64 * 10 + digit as u64;
276
65.5k
    let scale = if POINT { scale + 1 } else { 0 };
277
278
65.5k
    if let Some((next, bytes)) = bytes.split_first() {
279
64.8k
        let next = *next;
280
64.8k
        if POINT && BIG && scale >= 28 {
281
0
            if ROUND {
282
0
                maybe_round(data64 as u128, next, scale, POINT, NEG)
283
            } else {
284
0
                Err(Error::Underflow)
285
            }
286
64.8k
        } else if BIG && overflow_64(data64) {
287
1.80k
            handle_full_128::<POINT, NEG, ROUND>(data64 as u128, bytes, scale, next)
288
        } else {
289
63.0k
            byte_dispatch_u64::<POINT, NEG, true, BIG, false, ROUND>(bytes, data64, scale, next)
290
        }
291
    } else {
292
681
        let data: u128 = data64 as u128;
293
294
681
        handle_data::<NEG, true>(data, scale)
295
    }
296
65.5k
}
Unexecuted instantiation: rust_decimal::str::handle_digit_64::<false, false, true, false>
Unexecuted instantiation: rust_decimal::str::handle_digit_64::<false, true, false, false>
rust_decimal::str::handle_digit_64::<false, true, false, true>
Line
Count
Source
268
31.6k
fn handle_digit_64<const POINT: bool, const NEG: bool, const BIG: bool, const ROUND: bool>(
269
31.6k
    bytes: &[u8],
270
31.6k
    data64: u64,
271
31.6k
    scale: u8,
272
31.6k
    digit: u8,
273
31.6k
) -> Result<Decimal, Error> {
274
    // we have already validated that we cannot overflow
275
31.6k
    let data64 = data64 * 10 + digit as u64;
276
31.6k
    let scale = if POINT { scale + 1 } else { 0 };
277
278
31.6k
    if let Some((next, bytes)) = bytes.split_first() {
279
14.7k
        let next = *next;
280
14.7k
        if POINT && BIG && scale >= 28 {
281
0
            if ROUND {
282
0
                maybe_round(data64 as u128, next, scale, POINT, NEG)
283
            } else {
284
0
                Err(Error::Underflow)
285
            }
286
14.7k
        } else if BIG && overflow_64(data64) {
287
0
            handle_full_128::<POINT, NEG, ROUND>(data64 as u128, bytes, scale, next)
288
        } else {
289
14.7k
            byte_dispatch_u64::<POINT, NEG, true, BIG, false, ROUND>(bytes, data64, scale, next)
290
        }
291
    } else {
292
16.9k
        let data: u128 = data64 as u128;
293
294
16.9k
        handle_data::<NEG, true>(data, scale)
295
    }
296
31.6k
}
Unexecuted instantiation: rust_decimal::str::handle_digit_64::<false, true, true, false>
rust_decimal::str::handle_digit_64::<false, true, true, true>
Line
Count
Source
268
99.3k
fn handle_digit_64<const POINT: bool, const NEG: bool, const BIG: bool, const ROUND: bool>(
269
99.3k
    bytes: &[u8],
270
99.3k
    data64: u64,
271
99.3k
    scale: u8,
272
99.3k
    digit: u8,
273
99.3k
) -> Result<Decimal, Error> {
274
    // we have already validated that we cannot overflow
275
99.3k
    let data64 = data64 * 10 + digit as u64;
276
99.3k
    let scale = if POINT { scale + 1 } else { 0 };
277
278
99.3k
    if let Some((next, bytes)) = bytes.split_first() {
279
98.7k
        let next = *next;
280
98.7k
        if POINT && BIG && scale >= 28 {
281
0
            if ROUND {
282
0
                maybe_round(data64 as u128, next, scale, POINT, NEG)
283
            } else {
284
0
                Err(Error::Underflow)
285
            }
286
98.7k
        } else if BIG && overflow_64(data64) {
287
4.05k
            handle_full_128::<POINT, NEG, ROUND>(data64 as u128, bytes, scale, next)
288
        } else {
289
94.6k
            byte_dispatch_u64::<POINT, NEG, true, BIG, false, ROUND>(bytes, data64, scale, next)
290
        }
291
    } else {
292
615
        let data: u128 = data64 as u128;
293
294
615
        handle_data::<NEG, true>(data, scale)
295
    }
296
99.3k
}
rust_decimal::str::handle_digit_64::<true, true, true, true>
Line
Count
Source
268
47.0k
fn handle_digit_64<const POINT: bool, const NEG: bool, const BIG: bool, const ROUND: bool>(
269
47.0k
    bytes: &[u8],
270
47.0k
    data64: u64,
271
47.0k
    scale: u8,
272
47.0k
    digit: u8,
273
47.0k
) -> Result<Decimal, Error> {
274
    // we have already validated that we cannot overflow
275
47.0k
    let data64 = data64 * 10 + digit as u64;
276
47.0k
    let scale = if POINT { scale + 1 } else { 0 };
277
278
47.0k
    if let Some((next, bytes)) = bytes.split_first() {
279
46.6k
        let next = *next;
280
46.6k
        if POINT && BIG && scale >= 28 {
281
166
            if ROUND {
282
166
                maybe_round(data64 as u128, next, scale, POINT, NEG)
283
            } else {
284
0
                Err(Error::Underflow)
285
            }
286
46.4k
        } else if BIG && overflow_64(data64) {
287
2.31k
            handle_full_128::<POINT, NEG, ROUND>(data64 as u128, bytes, scale, next)
288
        } else {
289
44.1k
            byte_dispatch_u64::<POINT, NEG, true, BIG, false, ROUND>(bytes, data64, scale, next)
290
        }
291
    } else {
292
365
        let data: u128 = data64 as u128;
293
294
365
        handle_data::<NEG, true>(data, scale)
295
    }
296
47.0k
}
Unexecuted instantiation: rust_decimal::str::handle_digit_64::<true, true, true, false>
Unexecuted instantiation: rust_decimal::str::handle_digit_64::<true, true, false, false>
rust_decimal::str::handle_digit_64::<true, true, false, true>
Line
Count
Source
268
3.87k
fn handle_digit_64<const POINT: bool, const NEG: bool, const BIG: bool, const ROUND: bool>(
269
3.87k
    bytes: &[u8],
270
3.87k
    data64: u64,
271
3.87k
    scale: u8,
272
3.87k
    digit: u8,
273
3.87k
) -> Result<Decimal, Error> {
274
    // we have already validated that we cannot overflow
275
3.87k
    let data64 = data64 * 10 + digit as u64;
276
3.87k
    let scale = if POINT { scale + 1 } else { 0 };
277
278
3.87k
    if let Some((next, bytes)) = bytes.split_first() {
279
2.63k
        let next = *next;
280
2.63k
        if POINT && BIG && scale >= 28 {
281
0
            if ROUND {
282
0
                maybe_round(data64 as u128, next, scale, POINT, NEG)
283
            } else {
284
0
                Err(Error::Underflow)
285
            }
286
2.63k
        } else if BIG && overflow_64(data64) {
287
0
            handle_full_128::<POINT, NEG, ROUND>(data64 as u128, bytes, scale, next)
288
        } else {
289
2.63k
            byte_dispatch_u64::<POINT, NEG, true, BIG, false, ROUND>(bytes, data64, scale, next)
290
        }
291
    } else {
292
1.24k
        let data: u128 = data64 as u128;
293
294
1.24k
        handle_data::<NEG, true>(data, scale)
295
    }
296
3.87k
}
rust_decimal::str::handle_digit_64::<true, false, true, true>
Line
Count
Source
268
48.6k
fn handle_digit_64<const POINT: bool, const NEG: bool, const BIG: bool, const ROUND: bool>(
269
48.6k
    bytes: &[u8],
270
48.6k
    data64: u64,
271
48.6k
    scale: u8,
272
48.6k
    digit: u8,
273
48.6k
) -> Result<Decimal, Error> {
274
    // we have already validated that we cannot overflow
275
48.6k
    let data64 = data64 * 10 + digit as u64;
276
48.6k
    let scale = if POINT { scale + 1 } else { 0 };
277
278
48.6k
    if let Some((next, bytes)) = bytes.split_first() {
279
47.7k
        let next = *next;
280
47.7k
        if POINT && BIG && scale >= 28 {
281
166
            if ROUND {
282
166
                maybe_round(data64 as u128, next, scale, POINT, NEG)
283
            } else {
284
0
                Err(Error::Underflow)
285
            }
286
47.6k
        } else if BIG && overflow_64(data64) {
287
2.27k
            handle_full_128::<POINT, NEG, ROUND>(data64 as u128, bytes, scale, next)
288
        } else {
289
45.3k
            byte_dispatch_u64::<POINT, NEG, true, BIG, false, ROUND>(bytes, data64, scale, next)
290
        }
291
    } else {
292
888
        let data: u128 = data64 as u128;
293
294
888
        handle_data::<NEG, true>(data, scale)
295
    }
296
48.6k
}
Unexecuted instantiation: rust_decimal::str::handle_digit_64::<true, false, true, false>
rust_decimal::str::handle_digit_64::<true, false, false, true>
Line
Count
Source
268
22.3k
fn handle_digit_64<const POINT: bool, const NEG: bool, const BIG: bool, const ROUND: bool>(
269
22.3k
    bytes: &[u8],
270
22.3k
    data64: u64,
271
22.3k
    scale: u8,
272
22.3k
    digit: u8,
273
22.3k
) -> Result<Decimal, Error> {
274
    // we have already validated that we cannot overflow
275
22.3k
    let data64 = data64 * 10 + digit as u64;
276
22.3k
    let scale = if POINT { scale + 1 } else { 0 };
277
278
22.3k
    if let Some((next, bytes)) = bytes.split_first() {
279
19.1k
        let next = *next;
280
19.1k
        if POINT && BIG && scale >= 28 {
281
0
            if ROUND {
282
0
                maybe_round(data64 as u128, next, scale, POINT, NEG)
283
            } else {
284
0
                Err(Error::Underflow)
285
            }
286
19.1k
        } else if BIG && overflow_64(data64) {
287
0
            handle_full_128::<POINT, NEG, ROUND>(data64 as u128, bytes, scale, next)
288
        } else {
289
19.1k
            byte_dispatch_u64::<POINT, NEG, true, BIG, false, ROUND>(bytes, data64, scale, next)
290
        }
291
    } else {
292
3.23k
        let data: u128 = data64 as u128;
293
294
3.23k
        handle_data::<NEG, true>(data, scale)
295
    }
296
22.3k
}
Unexecuted instantiation: rust_decimal::str::handle_digit_64::<true, false, false, false>
297
298
#[inline(never)]
299
10.9k
fn handle_point<const NEG: bool, const HAS: bool, const BIG: bool, const ROUND: bool>(
300
10.9k
    bytes: &[u8],
301
10.9k
    data64: u64,
302
10.9k
    scale: u8,
303
10.9k
) -> Result<Decimal, Error> {
304
10.9k
    dispatch_next::<true, NEG, HAS, BIG, ROUND>(bytes, data64, scale)
305
10.9k
}
Unexecuted instantiation: rust_decimal::str::handle_point::<false, false, false, false>
Unexecuted instantiation: rust_decimal::str::handle_point::<false, false, false, true>
Unexecuted instantiation: rust_decimal::str::handle_point::<false, false, true, false>
Unexecuted instantiation: rust_decimal::str::handle_point::<false, false, true, true>
Unexecuted instantiation: rust_decimal::str::handle_point::<false, true, false, false>
rust_decimal::str::handle_point::<false, true, false, true>
Line
Count
Source
299
3.29k
fn handle_point<const NEG: bool, const HAS: bool, const BIG: bool, const ROUND: bool>(
300
3.29k
    bytes: &[u8],
301
3.29k
    data64: u64,
302
3.29k
    scale: u8,
303
3.29k
) -> Result<Decimal, Error> {
304
3.29k
    dispatch_next::<true, NEG, HAS, BIG, ROUND>(bytes, data64, scale)
305
3.29k
}
Unexecuted instantiation: rust_decimal::str::handle_point::<false, true, true, false>
rust_decimal::str::handle_point::<false, true, true, true>
Line
Count
Source
299
3.39k
fn handle_point<const NEG: bool, const HAS: bool, const BIG: bool, const ROUND: bool>(
300
3.39k
    bytes: &[u8],
301
3.39k
    data64: u64,
302
3.39k
    scale: u8,
303
3.39k
) -> Result<Decimal, Error> {
304
3.39k
    dispatch_next::<true, NEG, HAS, BIG, ROUND>(bytes, data64, scale)
305
3.39k
}
rust_decimal::str::handle_point::<true, true, true, true>
Line
Count
Source
299
2.90k
fn handle_point<const NEG: bool, const HAS: bool, const BIG: bool, const ROUND: bool>(
300
2.90k
    bytes: &[u8],
301
2.90k
    data64: u64,
302
2.90k
    scale: u8,
303
2.90k
) -> Result<Decimal, Error> {
304
2.90k
    dispatch_next::<true, NEG, HAS, BIG, ROUND>(bytes, data64, scale)
305
2.90k
}
Unexecuted instantiation: rust_decimal::str::handle_point::<true, true, true, false>
rust_decimal::str::handle_point::<true, true, false, true>
Line
Count
Source
299
1.31k
fn handle_point<const NEG: bool, const HAS: bool, const BIG: bool, const ROUND: bool>(
300
1.31k
    bytes: &[u8],
301
1.31k
    data64: u64,
302
1.31k
    scale: u8,
303
1.31k
) -> Result<Decimal, Error> {
304
1.31k
    dispatch_next::<true, NEG, HAS, BIG, ROUND>(bytes, data64, scale)
305
1.31k
}
Unexecuted instantiation: rust_decimal::str::handle_point::<true, true, false, false>
Unexecuted instantiation: rust_decimal::str::handle_point::<true, false, true, true>
Unexecuted instantiation: rust_decimal::str::handle_point::<true, false, true, false>
Unexecuted instantiation: rust_decimal::str::handle_point::<true, false, false, true>
Unexecuted instantiation: rust_decimal::str::handle_point::<true, false, false, false>
306
307
#[inline(never)]
308
14.0k
fn handle_separator<const POINT: bool, const NEG: bool, const BIG: bool, const ROUND: bool>(
309
14.0k
    bytes: &[u8],
310
14.0k
    data64: u64,
311
14.0k
    scale: u8,
312
14.0k
) -> Result<Decimal, Error> {
313
14.0k
    dispatch_next::<POINT, NEG, true, BIG, ROUND>(bytes, data64, scale)
314
14.0k
}
Unexecuted instantiation: rust_decimal::str::handle_separator::<false, false, false, false>
rust_decimal::str::handle_separator::<false, false, false, true>
Line
Count
Source
308
676
fn handle_separator<const POINT: bool, const NEG: bool, const BIG: bool, const ROUND: bool>(
309
676
    bytes: &[u8],
310
676
    data64: u64,
311
676
    scale: u8,
312
676
) -> Result<Decimal, Error> {
313
676
    dispatch_next::<POINT, NEG, true, BIG, ROUND>(bytes, data64, scale)
314
676
}
rust_decimal::str::handle_separator::<false, false, true, true>
Line
Count
Source
308
2.50k
fn handle_separator<const POINT: bool, const NEG: bool, const BIG: bool, const ROUND: bool>(
309
2.50k
    bytes: &[u8],
310
2.50k
    data64: u64,
311
2.50k
    scale: u8,
312
2.50k
) -> Result<Decimal, Error> {
313
2.50k
    dispatch_next::<POINT, NEG, true, BIG, ROUND>(bytes, data64, scale)
314
2.50k
}
Unexecuted instantiation: rust_decimal::str::handle_separator::<false, false, true, false>
Unexecuted instantiation: rust_decimal::str::handle_separator::<false, true, false, false>
rust_decimal::str::handle_separator::<false, true, false, true>
Line
Count
Source
308
600
fn handle_separator<const POINT: bool, const NEG: bool, const BIG: bool, const ROUND: bool>(
309
600
    bytes: &[u8],
310
600
    data64: u64,
311
600
    scale: u8,
312
600
) -> Result<Decimal, Error> {
313
600
    dispatch_next::<POINT, NEG, true, BIG, ROUND>(bytes, data64, scale)
314
600
}
Unexecuted instantiation: rust_decimal::str::handle_separator::<false, true, true, false>
rust_decimal::str::handle_separator::<false, true, true, true>
Line
Count
Source
308
1.78k
fn handle_separator<const POINT: bool, const NEG: bool, const BIG: bool, const ROUND: bool>(
309
1.78k
    bytes: &[u8],
310
1.78k
    data64: u64,
311
1.78k
    scale: u8,
312
1.78k
) -> Result<Decimal, Error> {
313
1.78k
    dispatch_next::<POINT, NEG, true, BIG, ROUND>(bytes, data64, scale)
314
1.78k
}
rust_decimal::str::handle_separator::<true, true, true, true>
Line
Count
Source
308
2.74k
fn handle_separator<const POINT: bool, const NEG: bool, const BIG: bool, const ROUND: bool>(
309
2.74k
    bytes: &[u8],
310
2.74k
    data64: u64,
311
2.74k
    scale: u8,
312
2.74k
) -> Result<Decimal, Error> {
313
2.74k
    dispatch_next::<POINT, NEG, true, BIG, ROUND>(bytes, data64, scale)
314
2.74k
}
Unexecuted instantiation: rust_decimal::str::handle_separator::<true, true, true, false>
Unexecuted instantiation: rust_decimal::str::handle_separator::<true, true, false, false>
rust_decimal::str::handle_separator::<true, true, false, true>
Line
Count
Source
308
239
fn handle_separator<const POINT: bool, const NEG: bool, const BIG: bool, const ROUND: bool>(
309
239
    bytes: &[u8],
310
239
    data64: u64,
311
239
    scale: u8,
312
239
) -> Result<Decimal, Error> {
313
239
    dispatch_next::<POINT, NEG, true, BIG, ROUND>(bytes, data64, scale)
314
239
}
rust_decimal::str::handle_separator::<true, false, true, true>
Line
Count
Source
308
4.97k
fn handle_separator<const POINT: bool, const NEG: bool, const BIG: bool, const ROUND: bool>(
309
4.97k
    bytes: &[u8],
310
4.97k
    data64: u64,
311
4.97k
    scale: u8,
312
4.97k
) -> Result<Decimal, Error> {
313
4.97k
    dispatch_next::<POINT, NEG, true, BIG, ROUND>(bytes, data64, scale)
314
4.97k
}
Unexecuted instantiation: rust_decimal::str::handle_separator::<true, false, true, false>
rust_decimal::str::handle_separator::<true, false, false, true>
Line
Count
Source
308
481
fn handle_separator<const POINT: bool, const NEG: bool, const BIG: bool, const ROUND: bool>(
309
481
    bytes: &[u8],
310
481
    data64: u64,
311
481
    scale: u8,
312
481
) -> Result<Decimal, Error> {
313
481
    dispatch_next::<POINT, NEG, true, BIG, ROUND>(bytes, data64, scale)
314
481
}
Unexecuted instantiation: rust_decimal::str::handle_separator::<true, false, false, false>
315
316
#[inline(never)]
317
#[cold]
318
0
fn tail_invalid_digit(digit: u8) -> Result<Decimal, Error> {
319
0
    match digit {
320
0
        b'.' => tail_error("Invalid decimal: two decimal points"),
321
0
        b'_' => tail_error("Invalid decimal: must start lead with a number"),
322
0
        _ => tail_error("Invalid decimal: unknown character"),
323
    }
324
0
}
325
326
#[inline(never)]
327
#[cold]
328
65.0k
fn handle_full_128<const POINT: bool, const NEG: bool, const ROUND: bool>(
329
65.0k
    mut data: u128,
330
65.0k
    bytes: &[u8],
331
65.0k
    scale: u8,
332
65.0k
    next_byte: u8,
333
65.0k
) -> Result<Decimal, Error> {
334
65.0k
    let b = next_byte;
335
1.92k
    match b {
336
63.1k
        b'0'..=b'9' => {
337
58.5k
            let digit = u32::from(b - b'0');
338
339
            // If the data is going to overflow then we should go into recovery mode
340
58.5k
            let next = (data * 10) + digit as u128;
341
58.5k
            if overflow_128(next) {
342
3.05k
                if !POINT {
343
18
                    return tail_error("Invalid decimal: overflow from too many digits");
344
3.03k
                }
345
346
3.03k
                if ROUND {
347
3.03k
                    maybe_round(data, next_byte, scale, POINT, NEG)
348
                } else {
349
0
                    Err(Error::Underflow)
350
                }
351
            } else {
352
55.5k
                data = next;
353
55.5k
                let scale = scale + POINT as u8;
354
55.5k
                if let Some((next, bytes)) = bytes.split_first() {
355
49.1k
                    let next = *next;
356
49.1k
                    if POINT && scale >= 28 {
357
914
                        if ROUND {
358
                            // If it is an underscore at the rounding position we require slightly different handling to look ahead another digit
359
914
                            if next == b'_' {
360
                                // Skip consecutive underscores to find the next actual character
361
146
                                let mut remaining_bytes = bytes;
362
146
                                let mut next_char = None;
363
664
                                while let Some((n, rest)) = remaining_bytes.split_first() {
364
623
                                    if *n != b'_' {
365
105
                                        next_char = Some(*n);
366
105
                                        break;
367
518
                                    }
368
518
                                    remaining_bytes = rest;
369
                                }
370
371
146
                                if let Some(ch) = next_char {
372
                                    // Skip underscores and use the next character for rounding
373
105
                                    maybe_round(data, ch, scale, POINT, NEG)
374
                                } else {
375
41
                                    handle_data::<NEG, true>(data, scale)
376
                                }
377
                            } else {
378
                                // Otherwise, we round as usual
379
768
                                maybe_round(data, next, scale, POINT, NEG)
380
                            }
381
                        } else {
382
0
                            Err(Error::Underflow)
383
                        }
384
                    } else {
385
48.2k
                        handle_full_128::<POINT, NEG, ROUND>(data, bytes, scale, next)
386
                    }
387
                } else {
388
6.32k
                    handle_data::<NEG, true>(data, scale)
389
                }
390
            }
391
        }
392
1.92k
        b'.' if !POINT => {
393
            // This call won't tail?
394
1.92k
            if let Some((next, bytes)) = bytes.split_first() {
395
1.92k
                handle_full_128::<true, NEG, ROUND>(data, bytes, scale, *next)
396
            } else {
397
0
                handle_data::<NEG, true>(data, scale)
398
            }
399
        }
400
        b'_' => {
401
4.54k
            if let Some((next, bytes)) = bytes.split_first() {
402
4.39k
                handle_full_128::<POINT, NEG, ROUND>(data, bytes, scale, *next)
403
            } else {
404
148
                handle_data::<NEG, true>(data, scale)
405
            }
406
        }
407
0
        b => tail_invalid_digit(b),
408
    }
409
65.0k
}
Unexecuted instantiation: rust_decimal::str::handle_full_128::<false, false, false>
rust_decimal::str::handle_full_128::<false, false, true>
Line
Count
Source
328
6.99k
fn handle_full_128<const POINT: bool, const NEG: bool, const ROUND: bool>(
329
6.99k
    mut data: u128,
330
6.99k
    bytes: &[u8],
331
6.99k
    scale: u8,
332
6.99k
    next_byte: u8,
333
6.99k
) -> Result<Decimal, Error> {
334
6.99k
    let b = next_byte;
335
676
    match b {
336
6.32k
        b'0'..=b'9' => {
337
6.13k
            let digit = u32::from(b - b'0');
338
339
            // If the data is going to overflow then we should go into recovery mode
340
6.13k
            let next = (data * 10) + digit as u128;
341
6.13k
            if overflow_128(next) {
342
7
                if !POINT {
343
7
                    return tail_error("Invalid decimal: overflow from too many digits");
344
0
                }
345
346
0
                if ROUND {
347
0
                    maybe_round(data, next_byte, scale, POINT, NEG)
348
                } else {
349
0
                    Err(Error::Underflow)
350
                }
351
            } else {
352
6.12k
                data = next;
353
6.12k
                let scale = scale + POINT as u8;
354
6.12k
                if let Some((next, bytes)) = bytes.split_first() {
355
5.03k
                    let next = *next;
356
5.03k
                    if POINT && scale >= 28 {
357
0
                        if ROUND {
358
                            // If it is an underscore at the rounding position we require slightly different handling to look ahead another digit
359
0
                            if next == b'_' {
360
                                // Skip consecutive underscores to find the next actual character
361
0
                                let mut remaining_bytes = bytes;
362
0
                                let mut next_char = None;
363
0
                                while let Some((n, rest)) = remaining_bytes.split_first() {
364
0
                                    if *n != b'_' {
365
0
                                        next_char = Some(*n);
366
0
                                        break;
367
0
                                    }
368
0
                                    remaining_bytes = rest;
369
                                }
370
371
0
                                if let Some(ch) = next_char {
372
                                    // Skip underscores and use the next character for rounding
373
0
                                    maybe_round(data, ch, scale, POINT, NEG)
374
                                } else {
375
0
                                    handle_data::<NEG, true>(data, scale)
376
                                }
377
                            } else {
378
                                // Otherwise, we round as usual
379
0
                                maybe_round(data, next, scale, POINT, NEG)
380
                            }
381
                        } else {
382
0
                            Err(Error::Underflow)
383
                        }
384
                    } else {
385
5.03k
                        handle_full_128::<POINT, NEG, ROUND>(data, bytes, scale, next)
386
                    }
387
                } else {
388
1.09k
                    handle_data::<NEG, true>(data, scale)
389
                }
390
            }
391
        }
392
676
        b'.' if !POINT => {
393
            // This call won't tail?
394
676
            if let Some((next, bytes)) = bytes.split_first() {
395
676
                handle_full_128::<true, NEG, ROUND>(data, bytes, scale, *next)
396
            } else {
397
0
                handle_data::<NEG, true>(data, scale)
398
            }
399
        }
400
        b'_' => {
401
188
            if let Some((next, bytes)) = bytes.split_first() {
402
162
                handle_full_128::<POINT, NEG, ROUND>(data, bytes, scale, *next)
403
            } else {
404
26
                handle_data::<NEG, true>(data, scale)
405
            }
406
        }
407
0
        b => tail_invalid_digit(b),
408
    }
409
6.99k
}
Unexecuted instantiation: rust_decimal::str::handle_full_128::<false, true, false>
rust_decimal::str::handle_full_128::<false, true, true>
Line
Count
Source
328
8.74k
fn handle_full_128<const POINT: bool, const NEG: bool, const ROUND: bool>(
329
8.74k
    mut data: u128,
330
8.74k
    bytes: &[u8],
331
8.74k
    scale: u8,
332
8.74k
    next_byte: u8,
333
8.74k
) -> Result<Decimal, Error> {
334
8.74k
    let b = next_byte;
335
1.24k
    match b {
336
7.49k
        b'0'..=b'9' => {
337
6.77k
            let digit = u32::from(b - b'0');
338
339
            // If the data is going to overflow then we should go into recovery mode
340
6.77k
            let next = (data * 10) + digit as u128;
341
6.77k
            if overflow_128(next) {
342
11
                if !POINT {
343
11
                    return tail_error("Invalid decimal: overflow from too many digits");
344
0
                }
345
346
0
                if ROUND {
347
0
                    maybe_round(data, next_byte, scale, POINT, NEG)
348
                } else {
349
0
                    Err(Error::Underflow)
350
                }
351
            } else {
352
6.76k
                data = next;
353
6.76k
                let scale = scale + POINT as u8;
354
6.76k
                if let Some((next, bytes)) = bytes.split_first() {
355
4.02k
                    let next = *next;
356
4.02k
                    if POINT && scale >= 28 {
357
0
                        if ROUND {
358
                            // If it is an underscore at the rounding position we require slightly different handling to look ahead another digit
359
0
                            if next == b'_' {
360
                                // Skip consecutive underscores to find the next actual character
361
0
                                let mut remaining_bytes = bytes;
362
0
                                let mut next_char = None;
363
0
                                while let Some((n, rest)) = remaining_bytes.split_first() {
364
0
                                    if *n != b'_' {
365
0
                                        next_char = Some(*n);
366
0
                                        break;
367
0
                                    }
368
0
                                    remaining_bytes = rest;
369
                                }
370
371
0
                                if let Some(ch) = next_char {
372
                                    // Skip underscores and use the next character for rounding
373
0
                                    maybe_round(data, ch, scale, POINT, NEG)
374
                                } else {
375
0
                                    handle_data::<NEG, true>(data, scale)
376
                                }
377
                            } else {
378
                                // Otherwise, we round as usual
379
0
                                maybe_round(data, next, scale, POINT, NEG)
380
                            }
381
                        } else {
382
0
                            Err(Error::Underflow)
383
                        }
384
                    } else {
385
4.02k
                        handle_full_128::<POINT, NEG, ROUND>(data, bytes, scale, next)
386
                    }
387
                } else {
388
2.74k
                    handle_data::<NEG, true>(data, scale)
389
                }
390
            }
391
        }
392
1.24k
        b'.' if !POINT => {
393
            // This call won't tail?
394
1.24k
            if let Some((next, bytes)) = bytes.split_first() {
395
1.24k
                handle_full_128::<true, NEG, ROUND>(data, bytes, scale, *next)
396
            } else {
397
0
                handle_data::<NEG, true>(data, scale)
398
            }
399
        }
400
        b'_' => {
401
717
            if let Some((next, bytes)) = bytes.split_first() {
402
659
                handle_full_128::<POINT, NEG, ROUND>(data, bytes, scale, *next)
403
            } else {
404
58
                handle_data::<NEG, true>(data, scale)
405
            }
406
        }
407
0
        b => tail_invalid_digit(b),
408
    }
409
8.74k
}
rust_decimal::str::handle_full_128::<true, true, true>
Line
Count
Source
328
30.0k
fn handle_full_128<const POINT: bool, const NEG: bool, const ROUND: bool>(
329
30.0k
    mut data: u128,
330
30.0k
    bytes: &[u8],
331
30.0k
    scale: u8,
332
30.0k
    next_byte: u8,
333
30.0k
) -> Result<Decimal, Error> {
334
30.0k
    let b = next_byte;
335
0
    match b {
336
30.0k
        b'0'..=b'9' => {
337
28.8k
            let digit = u32::from(b - b'0');
338
339
            // If the data is going to overflow then we should go into recovery mode
340
28.8k
            let next = (data * 10) + digit as u128;
341
28.8k
            if overflow_128(next) {
342
2.09k
                if !POINT {
343
0
                    return tail_error("Invalid decimal: overflow from too many digits");
344
2.09k
                }
345
346
2.09k
                if ROUND {
347
2.09k
                    maybe_round(data, next_byte, scale, POINT, NEG)
348
                } else {
349
0
                    Err(Error::Underflow)
350
                }
351
            } else {
352
26.7k
                data = next;
353
26.7k
                let scale = scale + POINT as u8;
354
26.7k
                if let Some((next, bytes)) = bytes.split_first() {
355
25.8k
                    let next = *next;
356
25.8k
                    if POINT && scale >= 28 {
357
481
                        if ROUND {
358
                            // If it is an underscore at the rounding position we require slightly different handling to look ahead another digit
359
481
                            if next == b'_' {
360
                                // Skip consecutive underscores to find the next actual character
361
35
                                let mut remaining_bytes = bytes;
362
35
                                let mut next_char = None;
363
233
                                while let Some((n, rest)) = remaining_bytes.split_first() {
364
214
                                    if *n != b'_' {
365
16
                                        next_char = Some(*n);
366
16
                                        break;
367
198
                                    }
368
198
                                    remaining_bytes = rest;
369
                                }
370
371
35
                                if let Some(ch) = next_char {
372
                                    // Skip underscores and use the next character for rounding
373
16
                                    maybe_round(data, ch, scale, POINT, NEG)
374
                                } else {
375
19
                                    handle_data::<NEG, true>(data, scale)
376
                                }
377
                            } else {
378
                                // Otherwise, we round as usual
379
446
                                maybe_round(data, next, scale, POINT, NEG)
380
                            }
381
                        } else {
382
0
                            Err(Error::Underflow)
383
                        }
384
                    } else {
385
25.3k
                        handle_full_128::<POINT, NEG, ROUND>(data, bytes, scale, next)
386
                    }
387
                } else {
388
952
                    handle_data::<NEG, true>(data, scale)
389
                }
390
            }
391
        }
392
0
        b'.' if !POINT => {
393
            // This call won't tail?
394
0
            if let Some((next, bytes)) = bytes.split_first() {
395
0
                handle_full_128::<true, NEG, ROUND>(data, bytes, scale, *next)
396
            } else {
397
0
                handle_data::<NEG, true>(data, scale)
398
            }
399
        }
400
        b'_' => {
401
1.18k
            if let Some((next, bytes)) = bytes.split_first() {
402
1.15k
                handle_full_128::<POINT, NEG, ROUND>(data, bytes, scale, *next)
403
            } else {
404
30
                handle_data::<NEG, true>(data, scale)
405
            }
406
        }
407
0
        b => tail_invalid_digit(b),
408
    }
409
30.0k
}
Unexecuted instantiation: rust_decimal::str::handle_full_128::<true, true, false>
rust_decimal::str::handle_full_128::<true, false, true>
Line
Count
Source
328
19.2k
fn handle_full_128<const POINT: bool, const NEG: bool, const ROUND: bool>(
329
19.2k
    mut data: u128,
330
19.2k
    bytes: &[u8],
331
19.2k
    scale: u8,
332
19.2k
    next_byte: u8,
333
19.2k
) -> Result<Decimal, Error> {
334
19.2k
    let b = next_byte;
335
0
    match b {
336
19.2k
        b'0'..=b'9' => {
337
16.7k
            let digit = u32::from(b - b'0');
338
339
            // If the data is going to overflow then we should go into recovery mode
340
16.7k
            let next = (data * 10) + digit as u128;
341
16.7k
            if overflow_128(next) {
342
943
                if !POINT {
343
0
                    return tail_error("Invalid decimal: overflow from too many digits");
344
943
                }
345
346
943
                if ROUND {
347
943
                    maybe_round(data, next_byte, scale, POINT, NEG)
348
                } else {
349
0
                    Err(Error::Underflow)
350
                }
351
            } else {
352
15.8k
                data = next;
353
15.8k
                let scale = scale + POINT as u8;
354
15.8k
                if let Some((next, bytes)) = bytes.split_first() {
355
14.3k
                    let next = *next;
356
14.3k
                    if POINT && scale >= 28 {
357
433
                        if ROUND {
358
                            // If it is an underscore at the rounding position we require slightly different handling to look ahead another digit
359
433
                            if next == b'_' {
360
                                // Skip consecutive underscores to find the next actual character
361
111
                                let mut remaining_bytes = bytes;
362
111
                                let mut next_char = None;
363
431
                                while let Some((n, rest)) = remaining_bytes.split_first() {
364
409
                                    if *n != b'_' {
365
89
                                        next_char = Some(*n);
366
89
                                        break;
367
320
                                    }
368
320
                                    remaining_bytes = rest;
369
                                }
370
371
111
                                if let Some(ch) = next_char {
372
                                    // Skip underscores and use the next character for rounding
373
89
                                    maybe_round(data, ch, scale, POINT, NEG)
374
                                } else {
375
22
                                    handle_data::<NEG, true>(data, scale)
376
                                }
377
                            } else {
378
                                // Otherwise, we round as usual
379
322
                                maybe_round(data, next, scale, POINT, NEG)
380
                            }
381
                        } else {
382
0
                            Err(Error::Underflow)
383
                        }
384
                    } else {
385
13.8k
                        handle_full_128::<POINT, NEG, ROUND>(data, bytes, scale, next)
386
                    }
387
                } else {
388
1.53k
                    handle_data::<NEG, true>(data, scale)
389
                }
390
            }
391
        }
392
0
        b'.' if !POINT => {
393
            // This call won't tail?
394
0
            if let Some((next, bytes)) = bytes.split_first() {
395
0
                handle_full_128::<true, NEG, ROUND>(data, bytes, scale, *next)
396
            } else {
397
0
                handle_data::<NEG, true>(data, scale)
398
            }
399
        }
400
        b'_' => {
401
2.45k
            if let Some((next, bytes)) = bytes.split_first() {
402
2.41k
                handle_full_128::<POINT, NEG, ROUND>(data, bytes, scale, *next)
403
            } else {
404
34
                handle_data::<NEG, true>(data, scale)
405
            }
406
        }
407
0
        b => tail_invalid_digit(b),
408
    }
409
19.2k
}
Unexecuted instantiation: rust_decimal::str::handle_full_128::<true, false, false>
410
411
#[inline(never)]
412
#[cold]
413
4.24k
fn maybe_round(mut data: u128, next_byte: u8, mut scale: u8, point: bool, negative: bool) -> Result<Decimal, Error> {
414
4.24k
    let digit = match next_byte {
415
4.24k
        b'0'..=b'9' => u32::from(next_byte - b'0'),
416
0
        b'_' => 0, // This is perhaps an error case, but keep this here for compatibility
417
0
        b'.' if !point => 0,
418
0
        b => return tail_invalid_digit(b),
419
    };
420
421
    // Round at midpoint
422
4.24k
    if digit >= 5 {
423
2.09k
        data += 1;
424
425
        // If the mantissa is now overflowing, round to the next
426
        // next least significant digit and discard precision
427
2.09k
        if overflow_128(data) {
428
0
            if scale == 0 {
429
0
                return tail_error("Invalid decimal: overflow from mantissa after rounding");
430
0
            }
431
0
            data += 4;
432
0
            data /= 10;
433
0
            scale -= 1;
434
2.09k
        }
435
2.14k
    }
436
437
4.24k
    if negative {
438
2.72k
        handle_data::<true, true>(data, scale)
439
    } else {
440
1.52k
        handle_data::<false, true>(data, scale)
441
    }
442
4.24k
}
443
444
#[inline(never)]
445
0
fn tail_no_has() -> Result<Decimal, Error> {
446
0
    tail_error("Invalid decimal: no digits found")
447
0
}
448
449
#[inline]
450
45.2k
fn handle_data<const NEG: bool, const HAS: bool>(data: u128, scale: u8) -> Result<Decimal, Error> {
451
45.2k
    debug_assert_eq!(data >> 96, 0);
452
45.2k
    if !HAS {
453
0
        tail_no_has()
454
    } else {
455
45.2k
        Ok(Decimal::from_parts(
456
45.2k
            data as u32,
457
45.2k
            (data >> 32) as u32,
458
45.2k
            (data >> 64) as u32,
459
45.2k
            NEG,
460
45.2k
            scale as u32,
461
45.2k
        ))
462
    }
463
45.2k
}
Unexecuted instantiation: rust_decimal::str::handle_data::<false, false>
rust_decimal::str::handle_data::<false, true>
Line
Count
Source
450
19.2k
fn handle_data<const NEG: bool, const HAS: bool>(data: u128, scale: u8) -> Result<Decimal, Error> {
451
19.2k
    debug_assert_eq!(data >> 96, 0);
452
19.2k
    if !HAS {
453
0
        tail_no_has()
454
    } else {
455
19.2k
        Ok(Decimal::from_parts(
456
19.2k
            data as u32,
457
19.2k
            (data >> 32) as u32,
458
19.2k
            (data >> 64) as u32,
459
19.2k
            NEG,
460
19.2k
            scale as u32,
461
19.2k
        ))
462
    }
463
19.2k
}
rust_decimal::str::handle_data::<true, true>
Line
Count
Source
450
25.9k
fn handle_data<const NEG: bool, const HAS: bool>(data: u128, scale: u8) -> Result<Decimal, Error> {
451
25.9k
    debug_assert_eq!(data >> 96, 0);
452
25.9k
    if !HAS {
453
0
        tail_no_has()
454
    } else {
455
25.9k
        Ok(Decimal::from_parts(
456
25.9k
            data as u32,
457
25.9k
            (data >> 32) as u32,
458
25.9k
            (data >> 64) as u32,
459
25.9k
            NEG,
460
25.9k
            scale as u32,
461
25.9k
        ))
462
    }
463
25.9k
}
Unexecuted instantiation: rust_decimal::str::handle_data::<true, false>
464
465
0
pub(crate) fn parse_str_radix_n(str: &str, radix: u32) -> Result<Decimal, Error> {
466
0
    if str.is_empty() {
467
0
        return Err(Error::from("Invalid decimal: empty"));
468
0
    }
469
0
    if radix < 2 {
470
0
        return Err(Error::from("Unsupported radix < 2"));
471
0
    }
472
0
    if radix > 36 {
473
        // As per trait documentation
474
0
        return Err(Error::from("Unsupported radix > 36"));
475
0
    }
476
477
0
    let mut offset = 0;
478
0
    let mut len = str.len();
479
0
    let bytes = str.as_bytes();
480
0
    let mut negative = false; // assume positive
481
482
    // handle the sign
483
0
    if bytes[offset] == b'-' {
484
0
        negative = true; // leading minus means negative
485
0
        offset += 1;
486
0
        len -= 1;
487
0
    } else if bytes[offset] == b'+' {
488
0
        // leading + allowed
489
0
        offset += 1;
490
0
        len -= 1;
491
0
    }
492
493
    // should now be at numeric part of the significand
494
0
    let mut digits_before_dot: i32 = -1; // digits before '.', -1 if no '.'
495
0
    let mut coeff = ArrayVec::<_, 96>::new(); // integer significand array
496
497
    // Supporting different radix
498
0
    let (max_n, max_alpha_lower, max_alpha_upper) = if radix <= 10 {
499
0
        (b'0' + (radix - 1) as u8, 0, 0)
500
    } else {
501
0
        let adj = (radix - 11) as u8;
502
0
        (b'9', adj + b'a', adj + b'A')
503
    };
504
505
    // Estimate the max precision. All in all, it needs to fit into 96 bits.
506
    // Rather than try to estimate, I've included the constants directly in here. We could,
507
    // perhaps, replace this with a formula if it's faster - though it does appear to be log2.
508
0
    let estimated_max_precision = match radix {
509
0
        2 => 96,
510
0
        3 => 61,
511
0
        4 => 48,
512
0
        5 => 42,
513
0
        6 => 38,
514
0
        7 => 35,
515
0
        8 => 32,
516
0
        9 => 31,
517
0
        10 => 28,
518
0
        11 => 28,
519
0
        12 => 27,
520
0
        13 => 26,
521
0
        14 => 26,
522
0
        15 => 25,
523
0
        16 => 24,
524
0
        17 => 24,
525
0
        18 => 24,
526
0
        19 => 23,
527
0
        20 => 23,
528
0
        21 => 22,
529
0
        22 => 22,
530
0
        23 => 22,
531
0
        24 => 21,
532
0
        25 => 21,
533
0
        26 => 21,
534
0
        27 => 21,
535
0
        28 => 20,
536
0
        29 => 20,
537
0
        30 => 20,
538
0
        31 => 20,
539
0
        32 => 20,
540
0
        33 => 20,
541
0
        34 => 19,
542
0
        35 => 19,
543
0
        36 => 19,
544
0
        _ => return Err(Error::from("Unsupported radix")),
545
    };
546
547
0
    let mut maybe_round = false;
548
0
    while len > 0 {
549
0
        let b = bytes[offset];
550
0
        match b {
551
0
            b'0'..=b'9' => {
552
0
                if b > max_n {
553
0
                    return Err(Error::from("Invalid decimal: invalid character"));
554
0
                }
555
0
                coeff.push(u32::from(b - b'0'));
556
0
                offset += 1;
557
0
                len -= 1;
558
559
                // If the coefficient is longer than the max, exit early
560
0
                if coeff.len() as u32 > estimated_max_precision {
561
0
                    maybe_round = true;
562
0
                    break;
563
0
                }
564
            }
565
0
            b'a'..=b'z' => {
566
0
                if b > max_alpha_lower {
567
0
                    return Err(Error::from("Invalid decimal: invalid character"));
568
0
                }
569
0
                coeff.push(u32::from(b - b'a') + 10);
570
0
                offset += 1;
571
0
                len -= 1;
572
573
0
                if coeff.len() as u32 > estimated_max_precision {
574
0
                    maybe_round = true;
575
0
                    break;
576
0
                }
577
            }
578
0
            b'A'..=b'Z' => {
579
0
                if b > max_alpha_upper {
580
0
                    return Err(Error::from("Invalid decimal: invalid character"));
581
0
                }
582
0
                coeff.push(u32::from(b - b'A') + 10);
583
0
                offset += 1;
584
0
                len -= 1;
585
586
0
                if coeff.len() as u32 > estimated_max_precision {
587
0
                    maybe_round = true;
588
0
                    break;
589
0
                }
590
            }
591
            b'.' => {
592
0
                if digits_before_dot >= 0 {
593
0
                    return Err(Error::from("Invalid decimal: two decimal points"));
594
0
                }
595
0
                digits_before_dot = coeff.len() as i32;
596
0
                offset += 1;
597
0
                len -= 1;
598
            }
599
            b'_' => {
600
                // Must start with a number...
601
0
                if coeff.is_empty() {
602
0
                    return Err(Error::from("Invalid decimal: must start lead with a number"));
603
0
                }
604
0
                offset += 1;
605
0
                len -= 1;
606
            }
607
0
            _ => return Err(Error::from("Invalid decimal: unknown character")),
608
        }
609
    }
610
611
    // If we exited before the end of the string then do some rounding if necessary
612
0
    if maybe_round && offset < bytes.len() {
613
0
        let next_byte = bytes[offset];
614
0
        let digit = match next_byte {
615
0
            b'0'..=b'9' => {
616
0
                if next_byte > max_n {
617
0
                    return Err(Error::from("Invalid decimal: invalid character"));
618
0
                }
619
0
                u32::from(next_byte - b'0')
620
            }
621
0
            b'a'..=b'z' => {
622
0
                if next_byte > max_alpha_lower {
623
0
                    return Err(Error::from("Invalid decimal: invalid character"));
624
0
                }
625
0
                u32::from(next_byte - b'a') + 10
626
            }
627
0
            b'A'..=b'Z' => {
628
0
                if next_byte > max_alpha_upper {
629
0
                    return Err(Error::from("Invalid decimal: invalid character"));
630
0
                }
631
0
                u32::from(next_byte - b'A') + 10
632
            }
633
0
            b'_' => 0,
634
            b'.' => {
635
                // Still an error if we have a second dp
636
0
                if digits_before_dot >= 0 {
637
0
                    return Err(Error::from("Invalid decimal: two decimal points"));
638
0
                }
639
0
                0
640
            }
641
0
            _ => return Err(Error::from("Invalid decimal: unknown character")),
642
        };
643
644
        // Round at midpoint
645
0
        let midpoint = if radix & 0x1 == 1 { radix / 2 } else { (radix + 1) / 2 };
646
0
        if digit >= midpoint {
647
0
            let mut index = coeff.len() - 1;
648
            loop {
649
0
                let new_digit = coeff[index] + 1;
650
0
                if new_digit <= 9 {
651
0
                    coeff[index] = new_digit;
652
0
                    break;
653
                } else {
654
0
                    coeff[index] = 0;
655
0
                    if index == 0 {
656
0
                        coeff.insert(0, 1u32);
657
0
                        digits_before_dot += 1;
658
0
                        coeff.pop();
659
0
                        break;
660
0
                    }
661
                }
662
0
                index -= 1;
663
            }
664
0
        }
665
0
    }
666
667
    // here when no characters left
668
0
    if coeff.is_empty() {
669
0
        return Err(Error::from("Invalid decimal: no digits found"));
670
0
    }
671
672
0
    let mut scale = if digits_before_dot >= 0 {
673
        // we had a decimal place so set the scale
674
0
        (coeff.len() as u32) - (digits_before_dot as u32)
675
    } else {
676
0
        0
677
    };
678
679
    // Parse this using specified radix
680
0
    let mut data = [0u32, 0u32, 0u32];
681
0
    let mut tmp = [0u32, 0u32, 0u32];
682
0
    let len = coeff.len();
683
0
    for (i, digit) in coeff.iter().enumerate() {
684
        // If the data is going to overflow then we should go into recovery mode
685
0
        tmp[0] = data[0];
686
0
        tmp[1] = data[1];
687
0
        tmp[2] = data[2];
688
0
        let overflow = mul_by_u32(&mut tmp, radix);
689
0
        if overflow > 0 {
690
            // This means that we have more data to process, that we're not sure what to do with.
691
            // This may or may not be an issue - depending on whether we're past a decimal point
692
            // or not.
693
0
            if (i as i32) < digits_before_dot && i + 1 < len {
694
0
                return Err(Error::from("Invalid decimal: overflow from too many digits"));
695
0
            }
696
697
0
            if *digit >= 5 {
698
0
                let carry = add_one_internal(&mut data);
699
0
                if carry > 0 {
700
                    // Highly unlikely scenario which is more indicative of a bug
701
0
                    return Err(Error::from("Invalid decimal: overflow when rounding"));
702
0
                }
703
0
            }
704
            // We're also one less digit so reduce the scale
705
0
            let diff = (len - i) as u32;
706
0
            if diff > scale {
707
0
                return Err(Error::from("Invalid decimal: overflow from scale mismatch"));
708
0
            }
709
0
            scale -= diff;
710
0
            break;
711
        } else {
712
0
            data[0] = tmp[0];
713
0
            data[1] = tmp[1];
714
0
            data[2] = tmp[2];
715
0
            let carry = add_by_internal_flattened(&mut data, *digit);
716
0
            if carry > 0 {
717
                // Highly unlikely scenario which is more indicative of a bug
718
0
                return Err(Error::from("Invalid decimal: overflow from carry"));
719
0
            }
720
        }
721
    }
722
723
0
    Ok(Decimal::from_parts(data[0], data[1], data[2], negative, scale))
724
0
}
725
726
#[cfg(test)]
727
mod test {
728
    use super::*;
729
    use crate::Decimal;
730
    use arrayvec::ArrayString;
731
    use core::{fmt::Write, str::FromStr};
732
733
    #[test]
734
    fn display_does_not_overflow_max_capacity() {
735
        let num = Decimal::from_str("1.2").unwrap();
736
        let mut buffer = ArrayString::<64>::new();
737
        buffer.write_fmt(format_args!("{num:.31}")).unwrap();
738
        assert_eq!("1.2000000000000000000000000000000", buffer.as_str());
739
    }
740
741
    #[test]
742
    fn from_str_rounding_0() {
743
        assert_eq!(
744
            parse_str_radix_10("1.234").unwrap().unpack(),
745
            Decimal::new(1234, 3).unpack()
746
        );
747
    }
748
749
    #[test]
750
    fn from_str_rounding_1() {
751
        assert_eq!(
752
            parse_str_radix_10("11111_11111_11111.11111_11111_11111")
753
                .unwrap()
754
                .unpack(),
755
            Decimal::from_i128_with_scale(11_111_111_111_111_111_111_111_111_111, 14).unpack()
756
        );
757
    }
758
759
    #[test]
760
    fn from_str_rounding_2() {
761
        assert_eq!(
762
            parse_str_radix_10("11111_11111_11111.11111_11111_11115")
763
                .unwrap()
764
                .unpack(),
765
            Decimal::from_i128_with_scale(11_111_111_111_111_111_111_111_111_112, 14).unpack()
766
        );
767
    }
768
769
    #[test]
770
    fn from_str_rounding_3() {
771
        assert_eq!(
772
            parse_str_radix_10("11111_11111_11111.11111_11111_11195")
773
                .unwrap()
774
                .unpack(),
775
            Decimal::from_i128_with_scale(1_111_111_111_111_111_111_111_111_1120, 14).unpack() // was Decimal::from_i128_with_scale(1_111_111_111_111_111_111_111_111_112, 13)
776
        );
777
    }
778
779
    #[test]
780
    fn from_str_rounding_4() {
781
        assert_eq!(
782
            parse_str_radix_10("99999_99999_99999.99999_99999_99995")
783
                .unwrap()
784
                .unpack(),
785
            Decimal::from_i128_with_scale(10_000_000_000_000_000_000_000_000_000, 13).unpack() // was Decimal::from_i128_with_scale(1_000_000_000_000_000_000_000_000_000, 12)
786
        );
787
    }
788
789
    #[test]
790
    fn from_str_no_rounding_0() {
791
        assert_eq!(
792
            parse_str_radix_10_exact("1.234").unwrap().unpack(),
793
            Decimal::new(1234, 3).unpack()
794
        );
795
    }
796
797
    #[test]
798
    fn from_str_no_rounding_1() {
799
        assert_eq!(
800
            parse_str_radix_10_exact("11111_11111_11111.11111_11111_11111"),
801
            Err(Error::Underflow)
802
        );
803
    }
804
805
    #[test]
806
    fn from_str_no_rounding_2() {
807
        assert_eq!(
808
            parse_str_radix_10_exact("11111_11111_11111.11111_11111_11115"),
809
            Err(Error::Underflow)
810
        );
811
    }
812
813
    #[test]
814
    fn from_str_no_rounding_3() {
815
        assert_eq!(
816
            parse_str_radix_10_exact("11111_11111_11111.11111_11111_11195"),
817
            Err(Error::Underflow)
818
        );
819
    }
820
821
    #[test]
822
    fn from_str_no_rounding_4() {
823
        assert_eq!(
824
            parse_str_radix_10_exact("99999_99999_99999.99999_99999_99995"),
825
            Err(Error::Underflow)
826
        );
827
    }
828
829
    #[test]
830
    fn from_str_many_pointless_chars() {
831
        assert_eq!(
832
            parse_str_radix_10("00________________________________________________________________001.1")
833
                .unwrap()
834
                .unpack(),
835
            Decimal::from_i128_with_scale(11, 1).unpack()
836
        );
837
    }
838
839
    #[test]
840
    fn from_str_leading_0s_1() {
841
        assert_eq!(
842
            parse_str_radix_10("00001.1").unwrap().unpack(),
843
            Decimal::from_i128_with_scale(11, 1).unpack()
844
        );
845
    }
846
847
    #[test]
848
    fn from_str_leading_0s_2() {
849
        assert_eq!(
850
            parse_str_radix_10("00000_00000_00000_00000_00001.00001")
851
                .unwrap()
852
                .unpack(),
853
            Decimal::from_i128_with_scale(100001, 5).unpack()
854
        );
855
    }
856
857
    #[test]
858
    fn from_str_leading_0s_3() {
859
        assert_eq!(
860
            parse_str_radix_10("0.00000_00000_00000_00000_00000_00100")
861
                .unwrap()
862
                .unpack(),
863
            Decimal::from_i128_with_scale(1, 28).unpack()
864
        );
865
    }
866
867
    #[test]
868
    fn from_str_trailing_0s_1() {
869
        assert_eq!(
870
            parse_str_radix_10("0.00001_00000_00000").unwrap().unpack(),
871
            Decimal::from_i128_with_scale(10_000_000_000, 15).unpack()
872
        );
873
    }
874
875
    #[test]
876
    fn from_str_trailing_0s_2() {
877
        assert_eq!(
878
            parse_str_radix_10("0.00001_00000_00000_00000_00000_00000")
879
                .unwrap()
880
                .unpack(),
881
            Decimal::from_i128_with_scale(100_000_000_000_000_000_000_000, 28).unpack()
882
        );
883
    }
884
885
    #[test]
886
    fn from_str_overflow_1() {
887
        assert_eq!(
888
            parse_str_radix_10("99999_99999_99999_99999_99999_99999.99999"),
889
            // The original implementation returned
890
            //              Ok(10000_00000_00000_00000_00000_0000)
891
            // Which is a bug!
892
            Err(Error::from("Invalid decimal: overflow from too many digits"))
893
        );
894
    }
895
896
    #[test]
897
    fn from_str_overflow_2() {
898
        assert!(
899
            parse_str_radix_10("99999_99999_99999_99999_99999_11111.11111").is_err(),
900
            // The original implementation is 'overflow from scale mismatch'
901
            // but we got rid of that now
902
        );
903
    }
904
905
    #[test]
906
    fn from_str_overflow_3() {
907
        assert!(
908
            parse_str_radix_10("99999_99999_99999_99999_99999_99994").is_err() // We could not get into 'overflow when rounding' or 'overflow from carry'
909
                                                                               // in the original implementation because the rounding logic before prevented it
910
        );
911
    }
912
913
    #[test]
914
    fn from_str_overflow_4() {
915
        assert_eq!(
916
            // This does not overflow, moving the decimal point 1 more step would result in
917
            // 'overflow from too many digits'
918
            parse_str_radix_10("99999_99999_99999_99999_99999_999.99")
919
                .unwrap()
920
                .unpack(),
921
            Decimal::from_i128_with_scale(10_000_000_000_000_000_000_000_000_000, 0).unpack()
922
        );
923
    }
924
925
    #[test]
926
    fn from_str_mantissa_overflow_1() {
927
        // reminder:
928
        assert_eq!(OVERFLOW_U96, 79_228_162_514_264_337_593_543_950_336);
929
        assert_eq!(
930
            parse_str_radix_10("79_228_162_514_264_337_593_543_950_33.56")
931
                .unwrap()
932
                .unpack(),
933
            Decimal::from_i128_with_scale(79_228_162_514_264_337_593_543_950_34, 0).unpack()
934
        );
935
        // This is a mantissa of OVERFLOW_U96 - 1 just before reaching the last digit.
936
        // Previously, this would return Err("overflow from mantissa after rounding")
937
        // instead of successfully rounding.
938
    }
939
940
    #[test]
941
    fn from_str_mantissa_overflow_2() {
942
        assert_eq!(
943
            parse_str_radix_10("79_228_162_514_264_337_593_543_950_335.6"),
944
            Err(Error::from("Invalid decimal: overflow from mantissa after rounding"))
945
        );
946
        // this case wants to round to 79_228_162_514_264_337_593_543_950_340.
947
        // (79_228_162_514_264_337_593_543_950_336 is OVERFLOW_U96 and too large
948
        // to fit in 96 bits) which is also too large for the mantissa so fails.
949
    }
950
951
    #[test]
952
    fn from_str_mantissa_overflow_3() {
953
        // this hits the other avoidable overflow case in maybe_round
954
        assert_eq!(
955
            parse_str_radix_10("7.92281625142643375935439503356").unwrap().unpack(),
956
            Decimal::from_i128_with_scale(79_228_162_514_264_337_593_543_950_34, 27).unpack()
957
        );
958
    }
959
960
    #[test]
961
    fn from_str_mantissa_overflow_4() {
962
        // Same test as above, however with underscores. This causes issues.
963
        assert_eq!(
964
            parse_str_radix_10("7.9_228_162_514_264_337_593_543_950_335_6")
965
                .unwrap()
966
                .unpack(),
967
            Decimal::from_i128_with_scale(79_228_162_514_264_337_593_543_950_34, 27).unpack()
968
        );
969
    }
970
971
    #[test]
972
    fn invalid_input_1() {
973
        assert_eq!(
974
            parse_str_radix_10("1.0000000000000000000000000000.5"),
975
            Err(Error::from("Invalid decimal: two decimal points"))
976
        );
977
    }
978
979
    #[test]
980
    fn invalid_input_2() {
981
        assert_eq!(
982
            parse_str_radix_10("1.0.5"),
983
            Err(Error::from("Invalid decimal: two decimal points"))
984
        );
985
    }
986
987
    #[test]
988
    fn character_at_rounding_position() {
989
        let tests = [
990
            // digit is at the rounding position
991
            (
992
                "1.000_000_000_000_000_000_000_000_000_04",
993
                Ok(Decimal::from_i128_with_scale(
994
                    1_000_000_000_000_000_000_000_000_000_0,
995
                    28,
996
                )),
997
            ),
998
            (
999
                "1.000_000_000_000_000_000_000_000_000_06",
1000
                Ok(Decimal::from_i128_with_scale(
1001
                    1_000_000_000_000_000_000_000_000_000_1,
1002
                    28,
1003
                )),
1004
            ),
1005
            // Decimal point is at the rounding position
1006
            (
1007
                "1_000_000_000_000_000_000_000_000_000_0.4",
1008
                Ok(Decimal::from_i128_with_scale(
1009
                    1_000_000_000_000_000_000_000_000_000_0,
1010
                    0,
1011
                )),
1012
            ),
1013
            (
1014
                "1_000_000_000_000_000_000_000_000_000_0.6",
1015
                Ok(Decimal::from_i128_with_scale(
1016
                    1_000_000_000_000_000_000_000_000_000_1,
1017
                    0,
1018
                )),
1019
            ),
1020
            // Placeholder is at the rounding position
1021
            (
1022
                "1.000_000_000_000_000_000_000_000_000_0_4",
1023
                Ok(Decimal::from_i128_with_scale(
1024
                    1_000_000_000_000_000_000_000_000_000_0,
1025
                    28,
1026
                )),
1027
            ),
1028
            (
1029
                "1.000_000_000_000_000_000_000_000_000_0_6",
1030
                Ok(Decimal::from_i128_with_scale(
1031
                    1_000_000_000_000_000_000_000_000_000_1,
1032
                    28,
1033
                )),
1034
            ),
1035
            // Multiple placeholders at rounding position
1036
            (
1037
                "1.000_000_000_000_000_000_000_000_000_0__4",
1038
                Ok(Decimal::from_i128_with_scale(
1039
                    1_000_000_000_000_000_000_000_000_000_0,
1040
                    28,
1041
                )),
1042
            ),
1043
            (
1044
                "1.000_000_000_000_000_000_000_000_000_0__6",
1045
                Ok(Decimal::from_i128_with_scale(
1046
                    1_000_000_000_000_000_000_000_000_000_1,
1047
                    28,
1048
                )),
1049
            ),
1050
            (
1051
                "1.234567890123456789012345678_9",
1052
                Ok(Decimal::from_i128_with_scale(12345678901234567890123456789, 28)),
1053
            ),
1054
            (
1055
                "0.234567890123456789012345678_9",
1056
                Ok(Decimal::from_i128_with_scale(2345678901234567890123456789, 28)),
1057
            ),
1058
            (
1059
                "0.1234567890123456789012345678_9",
1060
                Ok(Decimal::from_i128_with_scale(1234567890123456789012345679, 28)),
1061
            ),
1062
            (
1063
                "0.1234567890123456789012345678_4",
1064
                Ok(Decimal::from_i128_with_scale(1234567890123456789012345678, 28)),
1065
            ),
1066
        ];
1067
1068
        for (input, expected) in tests.iter() {
1069
            assert_eq!(parse_str_radix_10(input), *expected, "Test input {}", input);
1070
        }
1071
    }
1072
1073
    #[test]
1074
    fn from_str_edge_cases_1() {
1075
        assert_eq!(parse_str_radix_10(""), Err(Error::from("Invalid decimal: empty")));
1076
    }
1077
1078
    #[test]
1079
    fn from_str_edge_cases_2() {
1080
        assert_eq!(
1081
            parse_str_radix_10("0.1."),
1082
            Err(Error::from("Invalid decimal: two decimal points"))
1083
        );
1084
    }
1085
1086
    #[test]
1087
    fn from_str_edge_cases_3() {
1088
        assert_eq!(
1089
            parse_str_radix_10("_"),
1090
            Err(Error::from("Invalid decimal: must start lead with a number"))
1091
        );
1092
    }
1093
1094
    #[test]
1095
    fn from_str_edge_cases_4() {
1096
        assert_eq!(
1097
            parse_str_radix_10("1?2"),
1098
            Err(Error::from("Invalid decimal: unknown character"))
1099
        );
1100
    }
1101
1102
    #[test]
1103
    fn from_str_edge_cases_5() {
1104
        assert_eq!(
1105
            parse_str_radix_10("."),
1106
            Err(Error::from("Invalid decimal: no digits found"))
1107
        );
1108
    }
1109
1110
    #[test]
1111
    fn from_str_edge_cases_6() {
1112
        // Decimal::MAX + 0.99999
1113
        assert_eq!(
1114
            parse_str_radix_10("79_228_162_514_264_337_593_543_950_335.99999"),
1115
            Err(Error::from("Invalid decimal: overflow from mantissa after rounding"))
1116
        );
1117
    }
1118
}