lexical_util/format_flags.rs
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.
213macro_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.
220macro_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.
227macro_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.
234macro_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.
244pub 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.
248pub 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.
252pub const REQUIRED_EXPONENT_DIGITS: u128 = 1 << 2;
253
254/// Mantissa digits are required (either before or after the decimal point).
255pub const REQUIRED_MANTISSA_DIGITS: u128 = 1 << 3;
256
257/// At least 1 digit in the number is required.
258pub 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.
265pub const NO_POSITIVE_MANTISSA_SIGN: u128 = 1 << 4;
266
267/// Positive sign before the mantissa is required.
268pub const REQUIRED_MANTISSA_SIGN: u128 = 1 << 5;
269
270/// Exponent notation is not allowed.
271pub const NO_EXPONENT_NOTATION: u128 = 1 << 6;
272
273/// Positive sign before the exponent is not allowed.
274pub const NO_POSITIVE_EXPONENT_SIGN: u128 = 1 << 7;
275
276/// Positive sign before the exponent is required.
277pub 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.
284pub const NO_EXPONENT_WITHOUT_FRACTION: u128 = 1 << 9;
285
286/// Special (non-finite) values are not allowed.
287pub const NO_SPECIAL: u128 = 1 << 10;
288
289/// Special (non-finite) values are case-sensitive.
290pub 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.
306pub 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.
322pub 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.
328pub const REQUIRED_EXPONENT_NOTATION: u128 = 1 << 14;
329
330/// Exponent characters are case-sensitive.
331pub const CASE_SENSITIVE_EXPONENT: u128 = 1 << 15;
332
333/// Base prefixes are case-sensitive.
334pub const CASE_SENSITIVE_BASE_PREFIX: u128 = 1 << 16;
335
336/// Base suffixes are case-sensitive.
337pub const CASE_SENSITIVE_BASE_SUFFIX: u128 = 1 << 17;
338
339// Non-digit separator flags.
340const _: () = assert!(REQUIRED_INTEGER_DIGITS == 1);
341check_subsequent_flags!(REQUIRED_INTEGER_DIGITS, REQUIRED_FRACTION_DIGITS);
342check_subsequent_flags!(REQUIRED_FRACTION_DIGITS, REQUIRED_EXPONENT_DIGITS);
343check_subsequent_flags!(REQUIRED_EXPONENT_DIGITS, REQUIRED_MANTISSA_DIGITS);
344check_subsequent_flags!(REQUIRED_MANTISSA_DIGITS, NO_POSITIVE_MANTISSA_SIGN);
345check_subsequent_flags!(NO_POSITIVE_MANTISSA_SIGN, REQUIRED_MANTISSA_SIGN);
346check_subsequent_flags!(REQUIRED_MANTISSA_SIGN, NO_EXPONENT_NOTATION);
347check_subsequent_flags!(NO_EXPONENT_NOTATION, NO_POSITIVE_EXPONENT_SIGN);
348check_subsequent_flags!(NO_POSITIVE_EXPONENT_SIGN, REQUIRED_EXPONENT_SIGN);
349check_subsequent_flags!(REQUIRED_EXPONENT_SIGN, NO_EXPONENT_WITHOUT_FRACTION);
350check_subsequent_flags!(NO_EXPONENT_WITHOUT_FRACTION, NO_SPECIAL);
351check_subsequent_flags!(NO_SPECIAL, CASE_SENSITIVE_SPECIAL);
352check_subsequent_flags!(NO_SPECIAL, CASE_SENSITIVE_SPECIAL);
353check_subsequent_flags!(CASE_SENSITIVE_SPECIAL, NO_INTEGER_LEADING_ZEROS);
354check_subsequent_flags!(NO_INTEGER_LEADING_ZEROS, NO_FLOAT_LEADING_ZEROS);
355check_subsequent_flags!(NO_FLOAT_LEADING_ZEROS, REQUIRED_EXPONENT_NOTATION);
356check_subsequent_flags!(REQUIRED_EXPONENT_NOTATION, CASE_SENSITIVE_EXPONENT);
357check_subsequent_flags!(CASE_SENSITIVE_EXPONENT, CASE_SENSITIVE_BASE_PREFIX);
358check_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.
364pub const INTEGER_INTERNAL_DIGIT_SEPARATOR: u128 = 1 << 32;
365
366/// Digit separators are allowed between fraction digits.
367pub const FRACTION_INTERNAL_DIGIT_SEPARATOR: u128 = 1 << 33;
368
369/// Digit separators are allowed between exponent digits.
370pub const EXPONENT_INTERNAL_DIGIT_SEPARATOR: u128 = 1 << 34;
371
372/// A digit separator is allowed before any integer digits.
373pub const INTEGER_LEADING_DIGIT_SEPARATOR: u128 = 1 << 35;
374
375/// A digit separator is allowed before any fraction digits.
376pub const FRACTION_LEADING_DIGIT_SEPARATOR: u128 = 1 << 36;
377
378/// A digit separator is allowed before any exponent digits.
379pub const EXPONENT_LEADING_DIGIT_SEPARATOR: u128 = 1 << 37;
380
381/// A digit separator is allowed after any integer digits.
382pub const INTEGER_TRAILING_DIGIT_SEPARATOR: u128 = 1 << 38;
383
384/// A digit separator is allowed after any fraction digits.
385pub const FRACTION_TRAILING_DIGIT_SEPARATOR: u128 = 1 << 39;
386
387/// A digit separator is allowed after any exponent digits.
388pub const EXPONENT_TRAILING_DIGIT_SEPARATOR: u128 = 1 << 40;
389
390/// Multiple consecutive integer digit separators are allowed.
391pub const INTEGER_CONSECUTIVE_DIGIT_SEPARATOR: u128 = 1 << 41;
392
393/// Multiple consecutive fraction digit separators are allowed.
394pub const FRACTION_CONSECUTIVE_DIGIT_SEPARATOR: u128 = 1 << 42;
395
396/// Multiple consecutive exponent digit separators are allowed.
397pub const EXPONENT_CONSECUTIVE_DIGIT_SEPARATOR: u128 = 1 << 43;
398
399/// Digit separators are allowed between digits.
400pub 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.
406pub 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.
412pub 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.
418pub 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.
424pub const SPECIAL_DIGIT_SEPARATOR: u128 = 1 << 44;
425
426// Digit separator flags.
427const _: () = assert!(INTEGER_INTERNAL_DIGIT_SEPARATOR == 1 << 32);
428check_subsequent_flags!(INTEGER_INTERNAL_DIGIT_SEPARATOR, FRACTION_INTERNAL_DIGIT_SEPARATOR);
429check_subsequent_flags!(FRACTION_INTERNAL_DIGIT_SEPARATOR, EXPONENT_INTERNAL_DIGIT_SEPARATOR);
430check_subsequent_flags!(EXPONENT_INTERNAL_DIGIT_SEPARATOR, INTEGER_LEADING_DIGIT_SEPARATOR);
431check_subsequent_flags!(INTEGER_LEADING_DIGIT_SEPARATOR, FRACTION_LEADING_DIGIT_SEPARATOR);
432check_subsequent_flags!(FRACTION_LEADING_DIGIT_SEPARATOR, EXPONENT_LEADING_DIGIT_SEPARATOR);
433check_subsequent_flags!(EXPONENT_LEADING_DIGIT_SEPARATOR, INTEGER_TRAILING_DIGIT_SEPARATOR);
434check_subsequent_flags!(INTEGER_TRAILING_DIGIT_SEPARATOR, FRACTION_TRAILING_DIGIT_SEPARATOR);
435check_subsequent_flags!(FRACTION_TRAILING_DIGIT_SEPARATOR, EXPONENT_TRAILING_DIGIT_SEPARATOR);
436check_subsequent_flags!(EXPONENT_TRAILING_DIGIT_SEPARATOR, INTEGER_CONSECUTIVE_DIGIT_SEPARATOR);
437check_subsequent_flags!(INTEGER_CONSECUTIVE_DIGIT_SEPARATOR, FRACTION_CONSECUTIVE_DIGIT_SEPARATOR);
438check_subsequent_flags!(FRACTION_CONSECUTIVE_DIGIT_SEPARATOR, EXPONENT_CONSECUTIVE_DIGIT_SEPARATOR);
439check_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`.
445pub const DIGIT_SEPARATOR_SHIFT: i32 = 64;
446
447/// Mask to extract the digit separator character.
448pub const DIGIT_SEPARATOR: u128 = 0xFF << DIGIT_SEPARATOR_SHIFT;
449
450/// Shift to convert to and from a base prefix as a `u8`.
451pub const BASE_PREFIX_SHIFT: i32 = 88;
452
453/// Mask to extract the base prefix character.
454pub const BASE_PREFIX: u128 = 0xFF << BASE_PREFIX_SHIFT;
455
456/// Shift to convert to and from a base suffix as a `u8`.
457pub const BASE_SUFFIX_SHIFT: i32 = 96;
458
459/// Mask to extract the base suffix character.
460pub const BASE_SUFFIX: u128 = 0xFF << BASE_SUFFIX_SHIFT;
461
462/// Shift to convert to and from a mantissa radix as a `u32`.
463pub const MANTISSA_RADIX_SHIFT: i32 = 104;
464
465/// Mask to extract the mantissa radix: the radix for the significant digits.
466pub const MANTISSA_RADIX: u128 = 0xFF << MANTISSA_RADIX_SHIFT;
467
468/// Alias for [`MANTISSA_RADIX_SHIFT`].
469pub const RADIX_SHIFT: i32 = MANTISSA_RADIX_SHIFT;
470
471/// Alias for [`MANTISSA_RADIX`].
472pub const RADIX: u128 = MANTISSA_RADIX;
473
474/// Shift to convert to and from an exponent base as a `u32`.
475pub const EXPONENT_BASE_SHIFT: i32 = 112;
476
477/// Mask to extract the exponent base: the base the exponent is raised to.
478pub const EXPONENT_BASE: u128 = 0xFF << EXPONENT_BASE_SHIFT;
479
480/// Shift to convert to and from an exponent radix as a `u32`.
481pub const EXPONENT_RADIX_SHIFT: i32 = 120;
482
483/// Mask to extract the exponent radix: the radix for the exponent digits.
484pub 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.
490pub const RADIX_MASK: u128 = MANTISSA_RADIX | EXPONENT_RADIX;
491
492// Masks do not overlap.
493check_subsequent_masks!(DIGIT_SEPARATOR, BASE_PREFIX);
494check_subsequent_masks!(BASE_PREFIX, BASE_SUFFIX);
495check_subsequent_masks!(BASE_SUFFIX, MANTISSA_RADIX);
496check_subsequent_masks!(MANTISSA_RADIX, EXPONENT_BASE);
497check_subsequent_masks!(EXPONENT_BASE, EXPONENT_RADIX);
498
499// Check all our shifts shift the masks to a single byte.
500check_mask_shifts!(DIGIT_SEPARATOR, DIGIT_SEPARATOR_SHIFT);
501check_mask_shifts!(BASE_PREFIX, BASE_PREFIX_SHIFT);
502check_mask_shifts!(BASE_SUFFIX, BASE_SUFFIX_SHIFT);
503check_mask_shifts!(MANTISSA_RADIX, MANTISSA_RADIX_SHIFT);
504check_mask_shifts!(EXPONENT_BASE, EXPONENT_BASE_SHIFT);
505check_mask_shifts!(EXPONENT_RADIX, EXPONENT_RADIX_SHIFT);
506
507// Check masks don't overlap with neighboring flags.
508check_masks_and_flags!(DIGIT_SEPARATOR, SPECIAL_DIGIT_SEPARATOR);
509
510// HIDDEN MASKS
511// ------------
512
513/// Mask to extract the flag bits.
514#[doc(hidden)]
515pub 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)]
544pub 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)]
559pub 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)]
568pub 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)]
582pub 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)]
590pub 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)]
598pub 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)]
610pub const fn digit_separator(format: u128) -> u8 {
611 ((format & DIGIT_SEPARATOR) >> DIGIT_SEPARATOR_SHIFT) as u8
612}
613
614/// Extract the base prefix character from the format packed struct.
615#[doc(hidden)]
616#[inline(always)]
617pub const fn base_prefix(format: u128) -> u8 {
618 ((format & BASE_PREFIX) >> BASE_PREFIX_SHIFT) as u8
619}
620
621/// Extract the base suffix character from the format packed struct.
622#[doc(hidden)]
623#[inline(always)]
624pub const fn base_suffix(format: u128) -> u8 {
625 ((format & BASE_SUFFIX) >> BASE_SUFFIX_SHIFT) as u8
626}
627
628/// Extract the mantissa radix from the format packed struct.
629#[doc(hidden)]
630#[inline(always)]
631pub const fn mantissa_radix(format: u128) -> u32 {
632 ((format & MANTISSA_RADIX) >> MANTISSA_RADIX_SHIFT) as u32
633}
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)]
640pub const fn exponent_base(format: u128) -> u32 {
641 let radix = ((format & EXPONENT_BASE) >> EXPONENT_BASE_SHIFT) as u32;
642 if radix == 0 {
643 mantissa_radix(format)
644 } else {
645 radix
646 }
647}
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)]
654pub const fn exponent_radix(format: u128) -> u32 {
655 let radix = ((format & EXPONENT_RADIX) >> EXPONENT_RADIX_SHIFT) as u32;
656 if radix == 0 {
657 mantissa_radix(format)
658 } else {
659 radix
660 }
661}
662
663/// Extract a generic radix from the format and bitflags.
664#[doc(hidden)]
665#[inline(always)]
666pub 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)]
683pub 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)]
691const 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)]
704const 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)]
721const 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)]
729pub const fn is_valid_digit_separator(format: u128) -> bool {
730 let value = digit_separator(format);
731 if cfg!(feature = "format") {
732 is_valid_optional_control(format, value)
733 } else {
734 value == 0
735 }
736}
737
738/// Determine if the base prefix character is valid.
739#[inline(always)]
740pub const fn is_valid_base_prefix(format: u128) -> bool {
741 let value = base_prefix(format);
742 if cfg!(all(feature = "format", feature = "power-of-two")) {
743 is_valid_optional_control(format, value)
744 } else {
745 value == 0
746 }
747}
748
749/// Determine if the base suffix character is valid.
750#[inline(always)]
751pub const fn is_valid_base_suffix(format: u128) -> bool {
752 let value = base_suffix(format);
753 if cfg!(all(feature = "format", feature = "power-of-two")) {
754 is_valid_optional_control(format, value)
755 } else {
756 value == 0
757 }
758}
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"
763pub 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 if cfg!(not(feature = "format")) && digit_separator(format) != 0 {
767 // Digit separator set when not allowed.
768 false
769 } else {
770 let separator = digit_separator(format);
771 let prefix = base_prefix(format);
772 let suffix = base_suffix(format);
773 // Check all are optional, or enough are not present.
774 match (separator, prefix, suffix) {
775 (0, 0, 0) => true,
776 (_, 0, 0) => true,
777 (0, _, 0) => true,
778 (0, 0, _) => true,
779 // Can't have more than 1 0, check they're all different.
780 (x, y, z) => x != y && x != z && y != z,
781 }
782 }
783}
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"
790pub 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)]
818pub const fn is_valid_radix(radix: u32) -> bool {
819 if cfg!(feature = "radix") {
820 radix >= 2 && radix <= 36
821 } else if cfg!(feature = "power-of-two") {
822 matches!(radix, 2 | 4 | 8 | 10 | 16 | 32)
823 } else {
824 radix == 10
825 }
826}