Coverage Report

Created: 2026-02-26 07:12

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/rust-lexical/lexical-util/src/format_flags.rs
Line
Count
Source
1
//! Bitmask flags and masks for numeric formats.
2
//!
3
//! These bitflags and masks comprise a compressed struct as a 128-bit
4
//! integer, allowing its use in const generics. This comprises two parts:
5
//! flags designating which numerical components are valid in a string,
6
//! and masks to designate the control characters.
7
//!
8
//! The flags are designated in the lower 64 bits that modify
9
//! the syntax of strings that are parsed by lexical.
10
//!
11
//! Bits 8-32 are reserved for float component flags, such
12
//! as for example if base prefixes or postfixes are case-sensitive,
13
//! if leading zeros in a float are valid, etc.
14
//!
15
//! Bits 32-64 are reserved for digit separator flags. These
16
//! define which locations within a float or integer digit separators
17
//! are valid, for example, before any digits in the integer component,
18
//! whether consecutive digit separators are allowed, and more.
19
//!
20
//! ```text
21
//! 0   1   2   3   4   5   6   7   8   9   10  11  12  13  14  15  16
22
//! +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
23
//! |I/R|F/R|E/R|M/R|+/M|R/M|e/e|+/E|R/E|e/F|S/S|S/C|N/I|N/F|R/e|e/C|
24
//! +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
25
//!
26
//! 16  17  18  19  20  21  22  23  24  25  26  27  28  29  30  31  32
27
//! +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
28
//! |e/P|e/S|                                                       |
29
//! +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
30
//!
31
//! 32  33  34  35  36  37  38  39  40  41 42  43  44  45  46  47   48
32
//! +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
33
//! |I/I|F/I|E/I|I/L|F/L|E/L|I/T|F/T|E/T|I/C|F/C|E/C|S/D|           |
34
//! +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
35
//!
36
//! 48  49  50  51  52  53  54  55  56  57  58  59  60  62  62  63  64
37
//! +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
38
//! |                                                               |
39
//! +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
40
//!
41
//! Where:
42
//!     Non-Digit Separator Flags:
43
//!         I/R = Required integer digits.
44
//!         F/R = Required fraction digits.
45
//!         E/R = Required exponent digits.
46
//!         M/R = Required mantissa digits.
47
//!         +/M = No mantissa positive sign.
48
//!         R/M = Required positive sign.
49
//!         e/e = No exponent notation.
50
//!         +/E = No exponent positive sign.
51
//!         R/E = Required exponent sign.
52
//!         e/F = No exponent without fraction.
53
//!         S/S = No special (non-finite) values.
54
//!         S/C = Case-sensitive special (non-finite) values.
55
//!         N/I = No integer leading zeros.
56
//!         N/F = No float leading zeros.
57
//!         R/e = Required exponent characters.
58
//!         e/C = Case-sensitive exponent character.
59
//!         e/P = Case-sensitive base prefix.
60
//!         e/S = Case-sensitive base suffix.
61
//!
62
//!     Digit Separator Flags:
63
//!         I/I = Integer internal digit separator.
64
//!         F/I = Fraction internal digit separator.
65
//!         E/I = Exponent internal digit separator.
66
//!         I/L = Integer leading digit separator.
67
//!         F/L = Fraction leading digit separator.
68
//!         E/L = Exponent leading digit separator.
69
//!         I/T = Integer trailing digit separator.
70
//!         F/T = Fraction trailing digit separator.
71
//!         E/T = Exponent trailing digit separator.
72
//!         I/C = Integer consecutive digit separator.
73
//!         F/C = Fraction consecutive digit separator.
74
//!         E/C = Exponent consecutive digit separator.
75
//!         S/D = Special (non-finite) digit separator.
76
//! ```
77
//!
78
//! The upper 64-bits are designated for control characters and radixes,
79
//! such as the digit separator and base prefix characters, radixes,
80
//! and more.
81
//!
82
//! ```text
83
//! 64  65  66  67  68  69  70  71  72  73  74  75  76  77  78  79  80
84
//! +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
85
//! |     Digit Separator       |                                   |
86
//! +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
87
//!
88
//! 80  81  82  83  84  85  86  87  88  89  90  91  92  93  94  95  96
89
//! +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
90
//! |                               |        Base Prefix        |   |
91
//! +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
92
//!
93
//! 96  97  98  99  100 101 102 103 104 105 106 107 108 109 110 111 112
94
//! +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
95
//! |        Base Suffix        |   |    Mantissa Radix     |       |
96
//! +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
97
//!
98
//! 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128
99
//! +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
100
//! |     Exponent Base     |       |    Exponent Radix     |       |
101
//! +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
102
//! ```
103
//!
104
//!
105
//! Note:
106
//! -----
107
//!
108
//! In order to limit the format specification and avoid parsing
109
//! non-numerical data, all number formats require some significant
110
//! digits. Examples of always invalid numbers include:
111
//! - ` `
112
//! - `.`
113
//! - `e`
114
//! - `e7`
115
//!
116
//! Test Cases:
117
//! -----------
118
//!
119
//! The following test-cases are used to define whether a literal or
120
//! a string float is valid in a given language, and these tests are
121
//! used to denote features in pre-defined formats. Only a few
122
//! of these flags may modify the parsing behavior of integers.
123
//! Integer parsing is assumed to be derived from float parsing,
124
//! so if consecutive digit separators are valid in the integer
125
//! component of a float, they are also valid in an integer.
126
//!
127
//! ```text
128
//! 0: '.3'         // Non-required integer.
129
//! 1: '3.'         // Non-required fraction.
130
//! 2: '3e'         // Non-required exponent.
131
//! 3. '+3.0'       // Mantissa positive sign.
132
//! 4: '3.0e7'      // Exponent notation.
133
//! 5: '3.0e+7'     // Exponent positive sign.
134
//! 6. '3e7'        // Exponent notation without fraction.
135
//! 7: 'NaN'        // Special (non-finite) values.
136
//! 8: 'NAN'        // Case-sensitive special (non-finite) values.
137
//! 9: '3_4.01'     // Integer internal digit separator.
138
//! A: '3.0_1'      // Fraction internal digit separator.
139
//! B: '3.0e7_1'    // Exponent internal digit separator.
140
//! C: '_3.01'      // Integer leading digit separator.
141
//! D: '3._01'      // Fraction leading digit separator.
142
//! E: '3.0e_71'    // Exponent leading digit separator.
143
//! F: '3_.01'      // Integer trailing digit separator.
144
//! G: '3.01_'      // Fraction trailing digit separator.
145
//! H: '3.0e71_'    // Exponent trailing digit separator.
146
//! I: '3__4.01'    // Integer consecutive digit separator.
147
//! J: '3.0__1'     // Fraction consecutive digit separator.
148
//! K: '3.0e7__1'   // Exponent consecutive digit separator.
149
//! L: 'In_f'       // Special (non-finite) digit separator.
150
//! M: '010'        // No integer leading zeros.
151
//! N: '010.0'      // No float leading zeros.
152
//! O: '1.0'        // No required exponent notation.
153
//! P: '3.0E7'      // Case-insensitive exponent character.
154
//! P: '0x3.0'      // Case-insensitive base prefix.
155
//! P: '3.0H'       // Case-insensitive base postfix.
156
//! ```
157
//!
158
//! Currently Supported Programming and Data Languages:
159
//! ---------------------------------------------------
160
//!
161
//! 1. `Rust`
162
//! 2. `Python`
163
//! 3. `C++` (98, 03, 11, 14, 17)
164
//! 4. `C` (89, 90, 99, 11, 18)
165
//! 5. `Ruby`
166
//! 6. `Swift`
167
//! 7. `Go`
168
//! 8. `Haskell`
169
//! 9. `Javascript`
170
//! 10. `Perl`
171
//! 11. `PHP`
172
//! 12. `Java`
173
//! 13. `R`
174
//! 14. `Kotlin`
175
//! 15. `Julia`
176
//! 16. `C#` (ISO-1, ISO-2, 3, 4, 5, 6, 7)
177
//! 17. `Kawa`
178
//! 18. `Gambit-C`
179
//! 19. `Guile`
180
//! 20. `Clojure`
181
//! 21. `Erlang`
182
//! 22. `Elm`
183
//! 23. `Scala`
184
//! 24. `Elixir`
185
//! 25. `FORTRAN`
186
//! 26. `D`
187
//! 27. `Coffeescript`
188
//! 28. `Cobol`
189
//! 29. `F#`
190
//! 30. `Visual Basic`
191
//! 31. `OCaml`
192
//! 32. `Objective-C`
193
//! 33. `ReasonML`
194
//! 34. `Octave`
195
//! 35. `Matlab`
196
//! 36. `Zig`
197
//! 37. `SageMath`
198
//! 38. `JSON`
199
//! 39. `TOML`
200
//! 40. `XML`
201
//! 41. `SQLite`
202
//! 42. `PostgreSQL`
203
//! 43. `MySQL`
204
//! 44. `MongoDB`
205
206
#![cfg_attr(rustfmt, rustfmt::skip)]
207
#![doc(hidden)]
208
209
// ASSERTIONS
210
// ----------
211
212
// Ensure all our bit flags are valid.
213
macro_rules! check_subsequent_flags {
214
    ($x:ident, $y:ident) => {
215
        const _: () = assert!($x << 1 == $y);
216
    };
217
}
218
219
// Ensure all our bit masks don't overlap.
220
macro_rules! check_subsequent_masks {
221
    ($x:ident, $y:ident) => {
222
        const _: () = assert!($x & $y == 0);
223
    };
224
}
225
226
// Check all our masks are in the range `[0, 255]` after shifting.
227
macro_rules! check_mask_shifts {
228
    ($mask:ident, $shift:ident) => {
229
        const _: () = assert!(0 < $mask >> $shift && 255 >= $mask >> $shift);
230
    };
231
}
232
233
// Ensure all our bit masks don't overlap with existing flags.
234
macro_rules! check_masks_and_flags {
235
    ($x:ident, $y:ident) => {
236
        const _: () = assert!($x & $y == 0);
237
    };
238
}
239
240
// NON-DIGIT SEPARATOR FLAGS & MASKS
241
// ---------------------------------
242
243
/// Digits are required before the decimal point.
244
pub const REQUIRED_INTEGER_DIGITS: u128 = 1 << 0;
245
246
/// Digits are required after the decimal point.
247
/// This check will only occur if the decimal point is present.
248
pub const REQUIRED_FRACTION_DIGITS: u128 = 1 << 1;
249
250
/// Digits are required after the exponent character.
251
/// This check will only occur if the exponent character is present.
252
pub const REQUIRED_EXPONENT_DIGITS: u128 = 1 << 2;
253
254
/// Mantissa digits are required (either before or after the decimal point).
255
pub const REQUIRED_MANTISSA_DIGITS: u128 = 1 << 3;
256
257
/// At least 1 digit in the number is required.
258
pub const REQUIRED_DIGITS: u128 =
259
    REQUIRED_INTEGER_DIGITS |
260
    REQUIRED_FRACTION_DIGITS |
261
    REQUIRED_EXPONENT_DIGITS |
262
    REQUIRED_MANTISSA_DIGITS;
263
264
/// Positive sign before the mantissa is not allowed.
265
pub const NO_POSITIVE_MANTISSA_SIGN: u128 = 1 << 4;
266
267
/// Positive sign before the mantissa is required.
268
pub const REQUIRED_MANTISSA_SIGN: u128 = 1 << 5;
269
270
/// Exponent notation is not allowed.
271
pub const NO_EXPONENT_NOTATION: u128 = 1 << 6;
272
273
/// Positive sign before the exponent is not allowed.
274
pub const NO_POSITIVE_EXPONENT_SIGN: u128 = 1 << 7;
275
276
/// Positive sign before the exponent is required.
277
pub const REQUIRED_EXPONENT_SIGN: u128 = 1 << 8;
278
279
/// Exponent without a fraction component is not allowed.
280
///
281
/// This only checks if a decimal point precedes the exponent character.
282
/// To require fraction digits or exponent digits with this check,
283
/// please use the appropriate flags.
284
pub const NO_EXPONENT_WITHOUT_FRACTION: u128 = 1 << 9;
285
286
/// Special (non-finite) values are not allowed.
287
pub const NO_SPECIAL: u128 = 1 << 10;
288
289
/// Special (non-finite) values are case-sensitive.
290
pub const CASE_SENSITIVE_SPECIAL: u128 = 1 << 11;
291
292
/// Leading zeros before an integer value are not allowed.
293
///
294
/// If the value is a literal, then this distinction applies
295
/// when the value is treated like an integer literal, typically
296
/// when there is no decimal point. If the value is parsed,
297
/// then this distinction applies when the value as parsed
298
/// as an integer.
299
///
300
/// # Warning
301
///
302
/// This also does not mean that the value parsed will be correct,
303
/// for example, in languages like C, this will not auto-
304
/// deduce that the radix is 8 with leading zeros, for an octal
305
/// literal.
306
pub const NO_INTEGER_LEADING_ZEROS: u128 = 1 << 12;
307
308
/// Leading zeros before a float value are not allowed.
309
///
310
/// If the value is a literal, then this distinction applies
311
/// when the value is treated like an integer float, typically
312
/// when there is a decimal point. If the value is parsed,
313
/// then this distinction applies when the value as parsed
314
/// as a float.
315
///
316
/// # Warning
317
///
318
/// This also does not mean that the value parsed will be correct,
319
/// for example, in languages like C, this will not auto-
320
/// deduce that the radix is 8 with leading zeros, for an octal
321
/// literal.
322
pub const NO_FLOAT_LEADING_ZEROS: u128 = 1 << 13;
323
324
/// Exponent notation is required.
325
///
326
/// Valid floats must contain an exponent notation character, and if
327
/// applicable, a sign character and digits afterwards.
328
pub const REQUIRED_EXPONENT_NOTATION: u128 = 1 << 14;
329
330
/// Exponent characters are case-sensitive.
331
pub const CASE_SENSITIVE_EXPONENT: u128 = 1 << 15;
332
333
/// Base prefixes are case-sensitive.
334
pub const CASE_SENSITIVE_BASE_PREFIX: u128 = 1 << 16;
335
336
/// Base suffixes are case-sensitive.
337
pub const CASE_SENSITIVE_BASE_SUFFIX: u128 = 1 << 17;
338
339
// Non-digit separator flags.
340
const _: () = assert!(REQUIRED_INTEGER_DIGITS == 1);
341
check_subsequent_flags!(REQUIRED_INTEGER_DIGITS, REQUIRED_FRACTION_DIGITS);
342
check_subsequent_flags!(REQUIRED_FRACTION_DIGITS, REQUIRED_EXPONENT_DIGITS);
343
check_subsequent_flags!(REQUIRED_EXPONENT_DIGITS, REQUIRED_MANTISSA_DIGITS);
344
check_subsequent_flags!(REQUIRED_MANTISSA_DIGITS, NO_POSITIVE_MANTISSA_SIGN);
345
check_subsequent_flags!(NO_POSITIVE_MANTISSA_SIGN, REQUIRED_MANTISSA_SIGN);
346
check_subsequent_flags!(REQUIRED_MANTISSA_SIGN, NO_EXPONENT_NOTATION);
347
check_subsequent_flags!(NO_EXPONENT_NOTATION, NO_POSITIVE_EXPONENT_SIGN);
348
check_subsequent_flags!(NO_POSITIVE_EXPONENT_SIGN, REQUIRED_EXPONENT_SIGN);
349
check_subsequent_flags!(REQUIRED_EXPONENT_SIGN, NO_EXPONENT_WITHOUT_FRACTION);
350
check_subsequent_flags!(NO_EXPONENT_WITHOUT_FRACTION, NO_SPECIAL);
351
check_subsequent_flags!(NO_SPECIAL, CASE_SENSITIVE_SPECIAL);
352
check_subsequent_flags!(NO_SPECIAL, CASE_SENSITIVE_SPECIAL);
353
check_subsequent_flags!(CASE_SENSITIVE_SPECIAL, NO_INTEGER_LEADING_ZEROS);
354
check_subsequent_flags!(NO_INTEGER_LEADING_ZEROS, NO_FLOAT_LEADING_ZEROS);
355
check_subsequent_flags!(NO_FLOAT_LEADING_ZEROS, REQUIRED_EXPONENT_NOTATION);
356
check_subsequent_flags!(REQUIRED_EXPONENT_NOTATION, CASE_SENSITIVE_EXPONENT);
357
check_subsequent_flags!(CASE_SENSITIVE_EXPONENT, CASE_SENSITIVE_BASE_PREFIX);
358
check_subsequent_flags!(CASE_SENSITIVE_BASE_PREFIX, CASE_SENSITIVE_BASE_SUFFIX);
359
360
// DIGIT SEPARATOR FLAGS & MASKS
361
// -----------------------------
362
363
/// Digit separators are allowed between integer digits.
364
pub const INTEGER_INTERNAL_DIGIT_SEPARATOR: u128 = 1 << 32;
365
366
/// Digit separators are allowed between fraction digits.
367
pub const FRACTION_INTERNAL_DIGIT_SEPARATOR: u128 = 1 << 33;
368
369
/// Digit separators are allowed between exponent digits.
370
pub const EXPONENT_INTERNAL_DIGIT_SEPARATOR: u128 = 1 << 34;
371
372
/// A digit separator is allowed before any integer digits.
373
pub const INTEGER_LEADING_DIGIT_SEPARATOR: u128 = 1 << 35;
374
375
/// A digit separator is allowed before any fraction digits.
376
pub const FRACTION_LEADING_DIGIT_SEPARATOR: u128 = 1 << 36;
377
378
/// A digit separator is allowed before any exponent digits.
379
pub const EXPONENT_LEADING_DIGIT_SEPARATOR: u128 = 1 << 37;
380
381
/// A digit separator is allowed after any integer digits.
382
pub const INTEGER_TRAILING_DIGIT_SEPARATOR: u128 = 1 << 38;
383
384
/// A digit separator is allowed after any fraction digits.
385
pub const FRACTION_TRAILING_DIGIT_SEPARATOR: u128 = 1 << 39;
386
387
/// A digit separator is allowed after any exponent digits.
388
pub const EXPONENT_TRAILING_DIGIT_SEPARATOR: u128 = 1 << 40;
389
390
/// Multiple consecutive integer digit separators are allowed.
391
pub const INTEGER_CONSECUTIVE_DIGIT_SEPARATOR: u128 = 1 << 41;
392
393
/// Multiple consecutive fraction digit separators are allowed.
394
pub const FRACTION_CONSECUTIVE_DIGIT_SEPARATOR: u128 = 1 << 42;
395
396
/// Multiple consecutive exponent digit separators are allowed.
397
pub const EXPONENT_CONSECUTIVE_DIGIT_SEPARATOR: u128 = 1 << 43;
398
399
/// Digit separators are allowed between digits.
400
pub const INTERNAL_DIGIT_SEPARATOR: u128 =
401
    INTEGER_INTERNAL_DIGIT_SEPARATOR |
402
    FRACTION_INTERNAL_DIGIT_SEPARATOR |
403
    EXPONENT_INTERNAL_DIGIT_SEPARATOR;
404
405
/// A digit separator is allowed before any digits.
406
pub const LEADING_DIGIT_SEPARATOR: u128 =
407
    INTEGER_LEADING_DIGIT_SEPARATOR |
408
    FRACTION_LEADING_DIGIT_SEPARATOR |
409
    EXPONENT_LEADING_DIGIT_SEPARATOR;
410
411
/// A digit separator is allowed after any digits.
412
pub const TRAILING_DIGIT_SEPARATOR: u128 =
413
    INTEGER_TRAILING_DIGIT_SEPARATOR |
414
    FRACTION_TRAILING_DIGIT_SEPARATOR |
415
    EXPONENT_TRAILING_DIGIT_SEPARATOR;
416
417
/// Multiple consecutive digit separators are allowed.
418
pub const CONSECUTIVE_DIGIT_SEPARATOR: u128 =
419
    INTEGER_CONSECUTIVE_DIGIT_SEPARATOR |
420
    FRACTION_CONSECUTIVE_DIGIT_SEPARATOR |
421
    EXPONENT_CONSECUTIVE_DIGIT_SEPARATOR;
422
423
/// Any digit separators are allowed in special (non-finite) values.
424
pub const SPECIAL_DIGIT_SEPARATOR: u128 = 1 << 44;
425
426
// Digit separator flags.
427
const _: () = assert!(INTEGER_INTERNAL_DIGIT_SEPARATOR == 1 << 32);
428
check_subsequent_flags!(INTEGER_INTERNAL_DIGIT_SEPARATOR, FRACTION_INTERNAL_DIGIT_SEPARATOR);
429
check_subsequent_flags!(FRACTION_INTERNAL_DIGIT_SEPARATOR, EXPONENT_INTERNAL_DIGIT_SEPARATOR);
430
check_subsequent_flags!(EXPONENT_INTERNAL_DIGIT_SEPARATOR, INTEGER_LEADING_DIGIT_SEPARATOR);
431
check_subsequent_flags!(INTEGER_LEADING_DIGIT_SEPARATOR, FRACTION_LEADING_DIGIT_SEPARATOR);
432
check_subsequent_flags!(FRACTION_LEADING_DIGIT_SEPARATOR, EXPONENT_LEADING_DIGIT_SEPARATOR);
433
check_subsequent_flags!(EXPONENT_LEADING_DIGIT_SEPARATOR, INTEGER_TRAILING_DIGIT_SEPARATOR);
434
check_subsequent_flags!(INTEGER_TRAILING_DIGIT_SEPARATOR, FRACTION_TRAILING_DIGIT_SEPARATOR);
435
check_subsequent_flags!(FRACTION_TRAILING_DIGIT_SEPARATOR, EXPONENT_TRAILING_DIGIT_SEPARATOR);
436
check_subsequent_flags!(EXPONENT_TRAILING_DIGIT_SEPARATOR, INTEGER_CONSECUTIVE_DIGIT_SEPARATOR);
437
check_subsequent_flags!(INTEGER_CONSECUTIVE_DIGIT_SEPARATOR, FRACTION_CONSECUTIVE_DIGIT_SEPARATOR);
438
check_subsequent_flags!(FRACTION_CONSECUTIVE_DIGIT_SEPARATOR, EXPONENT_CONSECUTIVE_DIGIT_SEPARATOR);
439
check_subsequent_flags!(EXPONENT_CONSECUTIVE_DIGIT_SEPARATOR, SPECIAL_DIGIT_SEPARATOR);
440
441
// CONTROL CHARACTER & RADIX MASKS
442
// -------------------------------
443
444
/// Shift to convert to and from a digit separator as a `u8`.
445
pub const DIGIT_SEPARATOR_SHIFT: i32 = 64;
446
447
/// Mask to extract the digit separator character.
448
pub const DIGIT_SEPARATOR: u128 = 0xFF << DIGIT_SEPARATOR_SHIFT;
449
450
/// Shift to convert to and from a base prefix as a `u8`.
451
pub const BASE_PREFIX_SHIFT: i32 = 88;
452
453
/// Mask to extract the base prefix character.
454
pub const BASE_PREFIX: u128 = 0xFF << BASE_PREFIX_SHIFT;
455
456
/// Shift to convert to and from a base suffix as a `u8`.
457
pub const BASE_SUFFIX_SHIFT: i32 = 96;
458
459
/// Mask to extract the base suffix character.
460
pub const BASE_SUFFIX: u128 = 0xFF << BASE_SUFFIX_SHIFT;
461
462
/// Shift to convert to and from a mantissa radix as a `u32`.
463
pub const MANTISSA_RADIX_SHIFT: i32 = 104;
464
465
/// Mask to extract the mantissa radix: the radix for the significant digits.
466
pub const MANTISSA_RADIX: u128 = 0xFF << MANTISSA_RADIX_SHIFT;
467
468
/// Alias for [`MANTISSA_RADIX_SHIFT`].
469
pub const RADIX_SHIFT: i32 = MANTISSA_RADIX_SHIFT;
470
471
/// Alias for [`MANTISSA_RADIX`].
472
pub const RADIX: u128 = MANTISSA_RADIX;
473
474
/// Shift to convert to and from an exponent base as a `u32`.
475
pub const EXPONENT_BASE_SHIFT: i32 = 112;
476
477
/// Mask to extract the exponent base: the base the exponent is raised to.
478
pub const EXPONENT_BASE: u128 = 0xFF << EXPONENT_BASE_SHIFT;
479
480
/// Shift to convert to and from an exponent radix as a `u32`.
481
pub const EXPONENT_RADIX_SHIFT: i32 = 120;
482
483
/// Mask to extract the exponent radix: the radix for the exponent digits.
484
pub const EXPONENT_RADIX: u128 = 0xFF << EXPONENT_RADIX_SHIFT;
485
486
/// Mask to extract the exponent radix: the radix for the exponent digits.
487
///
488
/// This only extracts the radix bits, so negating it can be used
489
/// to see if any other custom settings were provided.
490
pub const RADIX_MASK: u128 = MANTISSA_RADIX | EXPONENT_RADIX;
491
492
// Masks do not overlap.
493
check_subsequent_masks!(DIGIT_SEPARATOR, BASE_PREFIX);
494
check_subsequent_masks!(BASE_PREFIX, BASE_SUFFIX);
495
check_subsequent_masks!(BASE_SUFFIX, MANTISSA_RADIX);
496
check_subsequent_masks!(MANTISSA_RADIX, EXPONENT_BASE);
497
check_subsequent_masks!(EXPONENT_BASE, EXPONENT_RADIX);
498
499
// Check all our shifts shift the masks to a single byte.
500
check_mask_shifts!(DIGIT_SEPARATOR, DIGIT_SEPARATOR_SHIFT);
501
check_mask_shifts!(BASE_PREFIX, BASE_PREFIX_SHIFT);
502
check_mask_shifts!(BASE_SUFFIX, BASE_SUFFIX_SHIFT);
503
check_mask_shifts!(MANTISSA_RADIX, MANTISSA_RADIX_SHIFT);
504
check_mask_shifts!(EXPONENT_BASE, EXPONENT_BASE_SHIFT);
505
check_mask_shifts!(EXPONENT_RADIX, EXPONENT_RADIX_SHIFT);
506
507
// Check masks don't overlap with neighboring flags.
508
check_masks_and_flags!(DIGIT_SEPARATOR, SPECIAL_DIGIT_SEPARATOR);
509
510
// HIDDEN MASKS
511
// ------------
512
513
/// Mask to extract the flag bits.
514
#[doc(hidden)]
515
pub const FLAG_MASK: u128 =
516
    REQUIRED_DIGITS |
517
    NO_POSITIVE_MANTISSA_SIGN |
518
    REQUIRED_MANTISSA_SIGN |
519
    NO_EXPONENT_NOTATION |
520
    NO_POSITIVE_EXPONENT_SIGN |
521
    REQUIRED_EXPONENT_SIGN |
522
    NO_EXPONENT_WITHOUT_FRACTION |
523
    NO_SPECIAL |
524
    CASE_SENSITIVE_SPECIAL |
525
    NO_INTEGER_LEADING_ZEROS |
526
    NO_FLOAT_LEADING_ZEROS |
527
    REQUIRED_EXPONENT_NOTATION |
528
    CASE_SENSITIVE_EXPONENT |
529
    CASE_SENSITIVE_BASE_PREFIX |
530
    CASE_SENSITIVE_BASE_SUFFIX |
531
    INTERNAL_DIGIT_SEPARATOR |
532
    LEADING_DIGIT_SEPARATOR |
533
    TRAILING_DIGIT_SEPARATOR |
534
    CONSECUTIVE_DIGIT_SEPARATOR |
535
    SPECIAL_DIGIT_SEPARATOR;
536
537
/// Mask to extract the flag bits controlling interface parsing.
538
///
539
/// This mask controls all the flags handled by the interface,
540
/// omitting those that are handled prior. This limits the
541
/// number of match paths required to determine the correct
542
/// interface.
543
#[doc(hidden)]
544
pub const INTERFACE_FLAG_MASK: u128 =
545
    REQUIRED_DIGITS |
546
    NO_EXPONENT_NOTATION |
547
    NO_POSITIVE_EXPONENT_SIGN |
548
    REQUIRED_EXPONENT_SIGN |
549
    NO_EXPONENT_WITHOUT_FRACTION |
550
    NO_FLOAT_LEADING_ZEROS |
551
    REQUIRED_EXPONENT_NOTATION |
552
    INTERNAL_DIGIT_SEPARATOR |
553
    LEADING_DIGIT_SEPARATOR |
554
    TRAILING_DIGIT_SEPARATOR |
555
    CONSECUTIVE_DIGIT_SEPARATOR;
556
557
/// Mask to extract digit separator flags.
558
#[doc(hidden)]
559
pub const DIGIT_SEPARATOR_FLAG_MASK: u128 =
560
    INTERNAL_DIGIT_SEPARATOR |
561
    LEADING_DIGIT_SEPARATOR |
562
    TRAILING_DIGIT_SEPARATOR |
563
    CONSECUTIVE_DIGIT_SEPARATOR |
564
    SPECIAL_DIGIT_SEPARATOR;
565
566
/// Mask to extract exponent flags.
567
#[doc(hidden)]
568
pub const EXPONENT_FLAG_MASK: u128 =
569
    REQUIRED_EXPONENT_DIGITS |
570
    NO_EXPONENT_NOTATION |
571
    NO_POSITIVE_EXPONENT_SIGN |
572
    REQUIRED_EXPONENT_SIGN |
573
    NO_EXPONENT_WITHOUT_FRACTION |
574
    REQUIRED_EXPONENT_NOTATION |
575
    EXPONENT_INTERNAL_DIGIT_SEPARATOR |
576
    EXPONENT_LEADING_DIGIT_SEPARATOR |
577
    EXPONENT_TRAILING_DIGIT_SEPARATOR |
578
    EXPONENT_CONSECUTIVE_DIGIT_SEPARATOR;
579
580
/// Mask to extract integer digit separator flags.
581
#[doc(hidden)]
582
pub const INTEGER_DIGIT_SEPARATOR_FLAG_MASK: u128 =
583
    INTEGER_INTERNAL_DIGIT_SEPARATOR |
584
    INTEGER_LEADING_DIGIT_SEPARATOR |
585
    INTEGER_TRAILING_DIGIT_SEPARATOR |
586
    INTEGER_CONSECUTIVE_DIGIT_SEPARATOR;
587
588
/// Mask to extract fraction digit separator flags.
589
#[doc(hidden)]
590
pub const FRACTION_DIGIT_SEPARATOR_FLAG_MASK: u128 =
591
    FRACTION_INTERNAL_DIGIT_SEPARATOR |
592
    FRACTION_LEADING_DIGIT_SEPARATOR |
593
    FRACTION_TRAILING_DIGIT_SEPARATOR |
594
    FRACTION_CONSECUTIVE_DIGIT_SEPARATOR;
595
596
/// Mask to extract exponent digit separator flags.
597
#[doc(hidden)]
598
pub const EXPONENT_DIGIT_SEPARATOR_FLAG_MASK: u128 =
599
    EXPONENT_INTERNAL_DIGIT_SEPARATOR |
600
    EXPONENT_LEADING_DIGIT_SEPARATOR |
601
    EXPONENT_TRAILING_DIGIT_SEPARATOR |
602
    EXPONENT_CONSECUTIVE_DIGIT_SEPARATOR;
603
604
// EXTRACTORS
605
// ----------
606
607
/// Extract the digit separator from the format packed struct.
608
#[doc(hidden)]
609
#[inline(always)]
610
28.4k
pub const fn digit_separator(format: u128) -> u8 {
611
28.4k
    ((format & DIGIT_SEPARATOR) >> DIGIT_SEPARATOR_SHIFT) as u8
612
28.4k
}
613
614
/// Extract the base prefix character from the format packed struct.
615
#[doc(hidden)]
616
#[inline(always)]
617
18.9k
pub const fn base_prefix(format: u128) -> u8 {
618
18.9k
    ((format & BASE_PREFIX) >> BASE_PREFIX_SHIFT) as u8
619
18.9k
}
620
621
/// Extract the base suffix character from the format packed struct.
622
#[doc(hidden)]
623
#[inline(always)]
624
18.9k
pub const fn base_suffix(format: u128) -> u8 {
625
18.9k
    ((format & BASE_SUFFIX) >> BASE_SUFFIX_SHIFT) as u8
626
18.9k
}
627
628
/// Extract the mantissa radix from the format packed struct.
629
#[doc(hidden)]
630
#[inline(always)]
631
28.4k
pub const fn mantissa_radix(format: u128) -> u32 {
632
28.4k
    ((format & MANTISSA_RADIX) >> MANTISSA_RADIX_SHIFT) as u32
633
28.4k
}
634
635
/// Extract the exponent base from the format packed struct.
636
///
637
/// If not provided, defaults to `mantissa_radix`.
638
#[doc(hidden)]
639
#[inline(always)]
640
9.46k
pub const fn exponent_base(format: u128) -> u32 {
641
9.46k
    let radix = ((format & EXPONENT_BASE) >> EXPONENT_BASE_SHIFT) as u32;
642
9.46k
    if radix == 0 {
643
9.46k
        mantissa_radix(format)
644
    } else {
645
0
        radix
646
    }
647
9.46k
}
648
649
/// Extract the exponent radix from the format packed struct.
650
///
651
/// If not provided, defaults to `mantissa_radix`.
652
#[doc(hidden)]
653
#[inline(always)]
654
9.46k
pub const fn exponent_radix(format: u128) -> u32 {
655
9.46k
    let radix = ((format & EXPONENT_RADIX) >> EXPONENT_RADIX_SHIFT) as u32;
656
9.46k
    if radix == 0 {
657
9.46k
        mantissa_radix(format)
658
    } else {
659
0
        radix
660
    }
661
9.46k
}
662
663
/// Extract a generic radix from the format and bitflags.
664
#[doc(hidden)]
665
#[inline(always)]
666
pub const fn radix_from_flags(format: u128, mask: u128, shift: i32) -> u32 {
667
    let radix = ((format & mask) >> shift) as u32;
668
    if radix == 0 {
669
        mantissa_radix(format)
670
    } else {
671
        radix
672
    }
673
}
674
675
// VALIDATORS
676
// ----------
677
678
// NOTE: All of these are only used when building formats so it doesn't matter if
679
// they have performance issues, since these will be built at compile time.
680
681
/// Determine if the provided exponent flags are valid.
682
#[inline(always)]
683
pub const fn is_valid_exponent_flags(format: u128) -> bool {
684
    // Both cannot be set.
685
    format & NO_EXPONENT_NOTATION == 0 || format & REQUIRED_EXPONENT_NOTATION == 0
686
}
687
688
/// Determine if an optional control character is valid.
689
#[doc(hidden)]
690
#[inline(always)]
691
const fn is_valid_optional_control_radix(radix: u32, value: u8) -> bool {
692
    // Validate the character isn't a digit or sign character, and is valid ASCII.
693
    use crate::ascii::is_valid_ascii;
694
    use crate::digit::char_is_digit_const;
695
    !char_is_digit_const(value, radix) &&
696
        value != b'+' &&
697
        value != b'-' &&
698
        (is_valid_ascii(value) || value == 0)
699
}
700
701
/// Determine if an optional control character is valid.
702
#[doc(hidden)]
703
#[inline(always)]
704
const fn is_valid_optional_control(format: u128, value: u8) -> bool {
705
    // Need to get the larger of the two radix values, since these
706
    // will be the characters that define the valid digits.
707
    // const fn doesn't support max as of 1.55 nightly.
708
    let mradix = mantissa_radix(format);
709
    let eradix = exponent_radix(format);
710
    let radix = if mradix > eradix {
711
        mradix
712
    } else {
713
        eradix
714
    };
715
    is_valid_optional_control_radix(radix, value)
716
}
717
718
/// Determine if an control character is valid.
719
#[doc(hidden)]
720
#[inline(always)]
721
const fn is_valid_control(format: u128, value: u8) -> bool {
722
    value != 0 && is_valid_optional_control(format, value)
723
}
724
725
/// Determine if the digit separator is valid.
726
///
727
/// Digit separators must not be valid digits or sign characters.
728
#[inline(always)]
729
9.46k
pub const fn is_valid_digit_separator(format: u128) -> bool {
730
9.46k
    let value = digit_separator(format);
731
9.46k
    if cfg!(feature = "format") {
732
0
        is_valid_optional_control(format, value)
733
    } else {
734
9.46k
        value == 0
735
    }
736
9.46k
}
737
738
/// Determine if the base prefix character is valid.
739
#[inline(always)]
740
9.46k
pub const fn is_valid_base_prefix(format: u128) -> bool {
741
9.46k
    let value = base_prefix(format);
742
9.46k
    if cfg!(all(feature = "format", feature = "power-of-two")) {
743
0
        is_valid_optional_control(format, value)
744
    } else {
745
9.46k
        value == 0
746
    }
747
9.46k
}
748
749
/// Determine if the base suffix character is valid.
750
#[inline(always)]
751
9.46k
pub const fn is_valid_base_suffix(format: u128) -> bool {
752
9.46k
    let value = base_suffix(format);
753
9.46k
    if cfg!(all(feature = "format", feature = "power-of-two")) {
754
0
        is_valid_optional_control(format, value)
755
    } else {
756
9.46k
        value == 0
757
    }
758
9.46k
}
759
760
/// Determine if all of the "punctuation" characters are valid.
761
#[inline(always)]
762
#[allow(clippy::if_same_then_else)] // reason="all are different logic conditions"
763
9.46k
pub const fn is_valid_punctuation(format: u128) -> bool {
764
    // All the checks against optional characters with mandatory are fine:
765
    // if they're not 0, then they can't overlap, and mandatory can't be 0.
766
9.46k
    if cfg!(not(feature = "format")) && digit_separator(format) != 0 {
767
        // Digit separator set when not allowed.
768
0
        false
769
    } else {
770
9.46k
        let separator = digit_separator(format);
771
9.46k
        let prefix = base_prefix(format);
772
9.46k
        let suffix = base_suffix(format);
773
        // Check all are optional, or enough are not present.
774
9.46k
        match (separator, prefix, suffix) {
775
9.46k
            (0, 0, 0) => true,
776
0
            (_, 0, 0) => true,
777
0
            (0, _, 0) => true,
778
0
            (0, 0, _) => true,
779
            // Can't have more than 1 0, check they're all different.
780
0
            (x, y, z) => x != y && x != z && y != z,
781
        }
782
    }
783
9.46k
}
784
785
/// Determine if all of the "punctuation" characters for the options API are valid.
786
#[doc(hidden)]
787
#[inline(always)]
788
#[allow(clippy::if_same_then_else)] // reason="all are different logic conditions"
789
#[allow(clippy::needless_bool)] // reason="not needless depending on the format condition"
790
pub const fn is_valid_options_punctuation(format: u128, exponent: u8, decimal_point: u8) -> bool {
791
    // All the checks against optional characters with mandatory are fine:
792
    // if they're not 0, then they can't overlap, and mandatory can't be 0.
793
    if !is_valid_control(format, decimal_point) || !is_valid_control(format, exponent) {
794
        // Must be in the valid range.
795
        false
796
    } else if decimal_point == exponent {
797
        // Can't have overlapping characters.
798
        false
799
    } else if cfg!(feature = "format") && digit_separator(format) == decimal_point {
800
        false
801
    } else if cfg!(feature = "format") && digit_separator(format) == exponent {
802
        false
803
    } else if cfg!(feature = "format") && base_prefix(format) == decimal_point {
804
        false
805
    } else if cfg!(feature = "format") && base_prefix(format) == exponent {
806
        false
807
    } else if cfg!(feature = "format") && base_suffix(format) == decimal_point {
808
        false
809
    } else if cfg!(feature = "format") && base_suffix(format) == exponent {
810
        false
811
    } else {
812
        true
813
    }
814
}
815
816
/// Determine if the radix is valid.
817
#[inline(always)]
818
28.4k
pub const fn is_valid_radix(radix: u32) -> bool {
819
28.4k
    if cfg!(feature = "radix") {
820
0
        radix >= 2 && radix <= 36
821
28.4k
    } else if cfg!(feature = "power-of-two") {
822
0
        matches!(radix, 2 | 4 | 8 | 10 | 16 | 32)
823
    } else {
824
28.4k
        radix == 10
825
    }
826
28.4k
}