//! Bitmask flags and masks for numeric formats.
//!
//! These bitflags and masks comprise a compressed struct as a 128-bit
//! integer, allowing its use in const generics. This comprises two parts:
//! flags designating which numerical components are valid in a string,
//! and masks to designate the control characters.
//!
//! The flags are designated in the lower 64 bits that modify
//! the syntax of strings that are parsed by lexical.
//!
//! Bits 8-32 are reserved for float component flags, such
//! as for example if base prefixes or postfixes are case-sensitive,
//! if leading zeros in a float are valid, etc.
//!
//! Bits 32-64 are reserved for digit separator flags. These
//! define which locations within a float or integer digit separators
//! are valid, for example, before any digits in the integer component,
//! whether consecutive digit separators are allowed, and more.
//!
//! ```text
//! 0   1   2   3   4   5   6   7   8   9   10  11  12  13  14  15  16
//! +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
//! |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|
//! +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
//!
//! 16  17  18  19  20  21  22  23  24  25  26  27  28  29  30  31  32
//! +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
//! |e/P|e/S|                                                       |
//! +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
//!
//! 32  33  34  35  36  37  38  39  40  41 42  43  44  45  46  47   48
//! +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
//! |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|           |
//! +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
//!
//! 48  49  50  51  52  53  54  55  56  57  58  59  60  62  62  63  64
//! +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
//! |                                                               |
//! +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
//!
//! Where:
//!     Non-Digit Separator Flags:
//!         I/R = Required integer digits.
//!         F/R = Required fraction digits.
//!         E/R = Required exponent digits.
//!         M/R = Required mantissa digits.
//!         +/M = No mantissa positive sign.
//!         R/M = Required positive sign.
//!         e/e = No exponent notation.
//!         +/E = No exponent positive sign.
//!         R/E = Required exponent sign.
//!         e/F = No exponent without fraction.
//!         S/S = No special (non-finite) values.
//!         S/C = Case-sensitive special (non-finite) values.
//!         N/I = No integer leading zeros.
//!         N/F = No float leading zeros.
//!         R/e = Required exponent characters.
//!         e/C = Case-sensitive exponent character.
//!         e/P = Case-sensitive base prefix.
//!         e/S = Case-sensitive base suffix.
//!
//!     Digit Separator Flags:
//!         I/I = Integer internal digit separator.
//!         F/I = Fraction internal digit separator.
//!         E/I = Exponent internal digit separator.
//!         I/L = Integer leading digit separator.
//!         F/L = Fraction leading digit separator.
//!         E/L = Exponent leading digit separator.
//!         I/T = Integer trailing digit separator.
//!         F/T = Fraction trailing digit separator.
//!         E/T = Exponent trailing digit separator.
//!         I/C = Integer consecutive digit separator.
//!         F/C = Fraction consecutive digit separator.
//!         E/C = Exponent consecutive digit separator.
//!         S/D = Special (non-finite) digit separator.
//! ```
//!
//! The upper 64-bits are designated for control characters and radixes,
//! such as the digit separator and base prefix characters, radixes,
//! and more.
//!
//! ```text
//! 64  65  66  67  68  69  70  71  72  73  74  75  76  77  78  79  80
//! +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
//! |     Digit Separator       |                                   |
//! +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
//!
//! 80  81  82  83  84  85  86  87  88  89  90  91  92  93  94  95  96
//! +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
//! |                               |        Base Prefix        |   |
//! +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
//!
//! 96  97  98  99  100 101 102 103 104 105 106 107 108 109 110 111 112
//! +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
//! |        Base Suffix        |   |    Mantissa Radix     |       |
//! +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
//!
//! 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128
//! +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
//! |     Exponent Base     |       |    Exponent Radix     |       |
//! +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
//! ```
//!
//!
//! Note:
//! -----
//!
//! In order to limit the format specification and avoid parsing
//! non-numerical data, all number formats require some significant
//! digits. Examples of always invalid numbers include:
//! - ` `
//! - `.`
//! - `e`
//! - `e7`
//!
//! Test Cases:
//! -----------
//!
//! The following test-cases are used to define whether a literal or
//! a string float is valid in a given language, and these tests are
//! used to denote features in pre-defined formats. Only a few
//! of these flags may modify the parsing behavior of integers.
//! Integer parsing is assumed to be derived from float parsing,
//! so if consecutive digit separators are valid in the integer
//! component of a float, they are also valid in an integer.
//!
//! ```text
//! 0: '.3'         // Non-required integer.
//! 1: '3.'         // Non-required fraction.
//! 2: '3e'         // Non-required exponent.
//! 3. '+3.0'       // Mantissa positive sign.
//! 4: '3.0e7'      // Exponent notation.
//! 5: '3.0e+7'     // Exponent positive sign.
//! 6. '3e7'        // Exponent notation without fraction.
//! 7: 'NaN'        // Special (non-finite) values.
//! 8: 'NAN'        // Case-sensitive special (non-finite) values.
//! 9: '3_4.01'     // Integer internal digit separator.
//! A: '3.0_1'      // Fraction internal digit separator.
//! B: '3.0e7_1'    // Exponent internal digit separator.
//! C: '_3.01'      // Integer leading digit separator.
//! D: '3._01'      // Fraction leading digit separator.
//! E: '3.0e_71'    // Exponent leading digit separator.
//! F: '3_.01'      // Integer trailing digit separator.
//! G: '3.01_'      // Fraction trailing digit separator.
//! H: '3.0e71_'    // Exponent trailing digit separator.
//! I: '3__4.01'    // Integer consecutive digit separator.
//! J: '3.0__1'     // Fraction consecutive digit separator.
//! K: '3.0e7__1'   // Exponent consecutive digit separator.
//! L: 'In_f'       // Special (non-finite) digit separator.
//! M: '010'        // No integer leading zeros.
//! N: '010.0'      // No float leading zeros.
//! O: '1.0'        // No required exponent notation.
//! P: '3.0E7'      // Case-insensitive exponent character.
//! P: '0x3.0'      // Case-insensitive base prefix.
//! P: '3.0H'       // Case-insensitive base postfix.
//! ```
//!
//! Currently Supported Programming and Data Languages:
//! ---------------------------------------------------
//!
//! 1. `Rust`
//! 2. `Python`
//! 3. `C++` (98, 03, 11, 14, 17)
//! 4. `C` (89, 90, 99, 11, 18)
//! 5. `Ruby`
//! 6. `Swift`
//! 7. `Go`
//! 8. `Haskell`
//! 9. `Javascript`
//! 10. `Perl`
//! 11. `PHP`
//! 12. `Java`
//! 13. `R`
//! 14. `Kotlin`
//! 15. `Julia`
//! 16. `C#` (ISO-1, ISO-2, 3, 4, 5, 6, 7)
//! 17. `Kawa`
//! 18. `Gambit-C`
//! 19. `Guile`
//! 20. `Clojure`
//! 21. `Erlang`
//! 22. `Elm`
//! 23. `Scala`
//! 24. `Elixir`
//! 25. `FORTRAN`
//! 26. `D`
//! 27. `Coffeescript`
//! 28. `Cobol`
//! 29. `F#`
//! 30. `Visual Basic`
//! 31. `OCaml`
//! 32. `Objective-C`
//! 33. `ReasonML`
//! 34. `Octave`
//! 35. `Matlab`
//! 36. `Zig`
//! 37. `SageMath`
//! 38. `JSON`
//! 39. `TOML`
//! 40. `XML`
//! 41. `SQLite`
//! 42. `PostgreSQL`
//! 43. `MySQL`
//! 44. `MongoDB`

#![cfg_attr(rustfmt, rustfmt::skip)]

use static_assertions::const_assert;

// ASSERTIONS
// ----------

// Ensure all our bit flags are valid.
macro_rules! check_subsequent_flags {
    ($x:ident, $y:ident) => {
        const_assert!($x << 1 == $y);
    };
}

// Ensure all our bit masks don't overlap.
macro_rules! check_subsequent_masks {
    ($x:ident, $y:ident) => {
        const_assert!($x & $y == 0);
    };
}

// Check all our masks are in the range `[0, 255]` after shifting.
macro_rules! check_mask_shifts {
    ($mask:ident, $shift:ident) => {
        const_assert!(0 < $mask >> $shift && 255 >= $mask >> $shift);
    };
}

// Ensure all our bit masks don't overlap with existing flags.
macro_rules! check_masks_and_flags {
    ($x:ident, $y:ident) => {
        const_assert!($x & $y == 0);
    };
}

// NON-DIGIT SEPARATOR FLAGS & MASKS
// ---------------------------------

/// Digits are required before the decimal point.
pub const REQUIRED_INTEGER_DIGITS: u128 = 1 << 0;

/// Digits are required after the decimal point.
/// This check will only occur if the decimal point is present.
pub const REQUIRED_FRACTION_DIGITS: u128 = 1 << 1;

/// Digits are required after the exponent character.
/// This check will only occur if the exponent character is present.
pub const REQUIRED_EXPONENT_DIGITS: u128 = 1 << 2;

/// Mantissa digits are required (either before or after the decimal point).
pub const REQUIRED_MANTISSA_DIGITS: u128 = 1 << 3;

/// At least 1 digit in the number is required.
pub const REQUIRED_DIGITS: u128 =
    REQUIRED_INTEGER_DIGITS |
    REQUIRED_FRACTION_DIGITS |
    REQUIRED_EXPONENT_DIGITS |
    REQUIRED_MANTISSA_DIGITS;

/// Positive sign before the mantissa is not allowed.
pub const NO_POSITIVE_MANTISSA_SIGN: u128 = 1 << 4;

/// Positive sign before the mantissa is required.
pub const REQUIRED_MANTISSA_SIGN: u128 = 1 << 5;

/// Exponent notation is not allowed.
pub const NO_EXPONENT_NOTATION: u128 = 1 << 6;

/// Positive sign before the exponent is not allowed.
pub const NO_POSITIVE_EXPONENT_SIGN: u128 = 1 << 7;

/// Positive sign before the exponent is required.
pub const REQUIRED_EXPONENT_SIGN: u128 = 1 << 8;

/// Exponent without a fraction component is not allowed.
///
/// This only checks if a decimal point precedes the exponent character.
/// To require fraction digits or exponent digits with this check,
/// please use the appropriate flags.
pub const NO_EXPONENT_WITHOUT_FRACTION: u128 = 1 << 9;

/// Special (non-finite) values are not allowed.
pub const NO_SPECIAL: u128 = 1 << 10;

/// Special (non-finite) values are case-sensitive.
pub const CASE_SENSITIVE_SPECIAL: u128 = 1 << 11;

/// Leading zeros before an integer value are not allowed.
///
/// If the value is a literal, then this distinction applies
/// when the value is treated like an integer literal, typically
/// when there is no decimal point. If the value is parsed,
/// then this distinction applies when the value as parsed
/// as an integer.
///
/// # Warning
///
/// This also does not mean that the value parsed will be correct,
/// for example, in languages like C, this will not auto-
/// deduce that the radix is 8 with leading zeros, for an octal
/// literal.
pub const NO_INTEGER_LEADING_ZEROS: u128 = 1 << 12;

/// Leading zeros before a float value are not allowed.
///
/// If the value is a literal, then this distinction applies
/// when the value is treated like an integer float, typically
/// when there is a decimal point. If the value is parsed,
/// then this distinction applies when the value as parsed
/// as a float.
///
/// # Warning
///
/// This also does not mean that the value parsed will be correct,
/// for example, in languages like C, this will not auto-
/// deduce that the radix is 8 with leading zeros, for an octal
/// literal.
pub const NO_FLOAT_LEADING_ZEROS: u128 = 1 << 13;

/// Exponent notation is required.
///
/// Valid floats must contain an exponent notation character, and if
/// applicable, a sign character and digits afterwards.
pub const REQUIRED_EXPONENT_NOTATION: u128 = 1 << 14;

/// Exponent characters are case-sensitive.
pub const CASE_SENSITIVE_EXPONENT: u128 = 1 << 15;

/// Base prefixes are case-sensitive.
pub const CASE_SENSITIVE_BASE_PREFIX: u128 = 1 << 16;

/// Base suffixes are case-sensitive.
pub const CASE_SENSITIVE_BASE_SUFFIX: u128 = 1 << 17;

// Non-digit separator flags.
const_assert!(REQUIRED_INTEGER_DIGITS == 1);
check_subsequent_flags!(REQUIRED_INTEGER_DIGITS, REQUIRED_FRACTION_DIGITS);
check_subsequent_flags!(REQUIRED_FRACTION_DIGITS, REQUIRED_EXPONENT_DIGITS);
check_subsequent_flags!(REQUIRED_EXPONENT_DIGITS, REQUIRED_MANTISSA_DIGITS);
check_subsequent_flags!(REQUIRED_MANTISSA_DIGITS, NO_POSITIVE_MANTISSA_SIGN);
check_subsequent_flags!(NO_POSITIVE_MANTISSA_SIGN, REQUIRED_MANTISSA_SIGN);
check_subsequent_flags!(REQUIRED_MANTISSA_SIGN, NO_EXPONENT_NOTATION);
check_subsequent_flags!(NO_EXPONENT_NOTATION, NO_POSITIVE_EXPONENT_SIGN);
check_subsequent_flags!(NO_POSITIVE_EXPONENT_SIGN, REQUIRED_EXPONENT_SIGN);
check_subsequent_flags!(REQUIRED_EXPONENT_SIGN, NO_EXPONENT_WITHOUT_FRACTION);
check_subsequent_flags!(NO_EXPONENT_WITHOUT_FRACTION, NO_SPECIAL);
check_subsequent_flags!(NO_SPECIAL, CASE_SENSITIVE_SPECIAL);
check_subsequent_flags!(NO_SPECIAL, CASE_SENSITIVE_SPECIAL);
check_subsequent_flags!(CASE_SENSITIVE_SPECIAL, NO_INTEGER_LEADING_ZEROS);
check_subsequent_flags!(NO_INTEGER_LEADING_ZEROS, NO_FLOAT_LEADING_ZEROS);
check_subsequent_flags!(NO_FLOAT_LEADING_ZEROS, REQUIRED_EXPONENT_NOTATION);
check_subsequent_flags!(REQUIRED_EXPONENT_NOTATION, CASE_SENSITIVE_EXPONENT);
check_subsequent_flags!(CASE_SENSITIVE_EXPONENT, CASE_SENSITIVE_BASE_PREFIX);
check_subsequent_flags!(CASE_SENSITIVE_BASE_PREFIX, CASE_SENSITIVE_BASE_SUFFIX);

// DIGIT SEPARATOR FLAGS & MASKS
// -----------------------------

/// Digit separators are allowed between integer digits.
pub const INTEGER_INTERNAL_DIGIT_SEPARATOR: u128 = 1 << 32;

/// Digit separators are allowed between fraction digits.
pub const FRACTION_INTERNAL_DIGIT_SEPARATOR: u128 = 1 << 33;

/// Digit separators are allowed between exponent digits.
pub const EXPONENT_INTERNAL_DIGIT_SEPARATOR: u128 = 1 << 34;

/// A digit separator is allowed before any integer digits.
pub const INTEGER_LEADING_DIGIT_SEPARATOR: u128 = 1 << 35;

/// A digit separator is allowed before any fraction digits.
pub const FRACTION_LEADING_DIGIT_SEPARATOR: u128 = 1 << 36;

/// A digit separator is allowed before any exponent digits.
pub const EXPONENT_LEADING_DIGIT_SEPARATOR: u128 = 1 << 37;

/// A digit separator is allowed after any integer digits.
pub const INTEGER_TRAILING_DIGIT_SEPARATOR: u128 = 1 << 38;

/// A digit separator is allowed after any fraction digits.
pub const FRACTION_TRAILING_DIGIT_SEPARATOR: u128 = 1 << 39;

/// A digit separator is allowed after any exponent digits.
pub const EXPONENT_TRAILING_DIGIT_SEPARATOR: u128 = 1 << 40;

/// Multiple consecutive integer digit separators are allowed.
pub const INTEGER_CONSECUTIVE_DIGIT_SEPARATOR: u128 = 1 << 41;

/// Multiple consecutive fraction digit separators are allowed.
pub const FRACTION_CONSECUTIVE_DIGIT_SEPARATOR: u128 = 1 << 42;

/// Multiple consecutive exponent digit separators are allowed.
pub const EXPONENT_CONSECUTIVE_DIGIT_SEPARATOR: u128 = 1 << 43;

/// Digit separators are allowed between digits.
pub const INTERNAL_DIGIT_SEPARATOR: u128 =
    INTEGER_INTERNAL_DIGIT_SEPARATOR |
    FRACTION_INTERNAL_DIGIT_SEPARATOR |
    EXPONENT_INTERNAL_DIGIT_SEPARATOR;

/// A digit separator is allowed before any digits.
pub const LEADING_DIGIT_SEPARATOR: u128 =
    INTEGER_LEADING_DIGIT_SEPARATOR |
    FRACTION_LEADING_DIGIT_SEPARATOR |
    EXPONENT_LEADING_DIGIT_SEPARATOR;

/// A digit separator is allowed after any digits.
pub const TRAILING_DIGIT_SEPARATOR: u128 =
    INTEGER_TRAILING_DIGIT_SEPARATOR |
    FRACTION_TRAILING_DIGIT_SEPARATOR |
    EXPONENT_TRAILING_DIGIT_SEPARATOR;

/// Multiple consecutive digit separators are allowed.
pub const CONSECUTIVE_DIGIT_SEPARATOR: u128 =
    INTEGER_CONSECUTIVE_DIGIT_SEPARATOR |
    FRACTION_CONSECUTIVE_DIGIT_SEPARATOR |
    EXPONENT_CONSECUTIVE_DIGIT_SEPARATOR;

/// Any digit separators are allowed in special (non-finite) values.
pub const SPECIAL_DIGIT_SEPARATOR: u128 = 1 << 44;

// Digit separator flags.
const_assert!(INTEGER_INTERNAL_DIGIT_SEPARATOR == 1 << 32);
check_subsequent_flags!(INTEGER_INTERNAL_DIGIT_SEPARATOR, FRACTION_INTERNAL_DIGIT_SEPARATOR);
check_subsequent_flags!(FRACTION_INTERNAL_DIGIT_SEPARATOR, EXPONENT_INTERNAL_DIGIT_SEPARATOR);
check_subsequent_flags!(EXPONENT_INTERNAL_DIGIT_SEPARATOR, INTEGER_LEADING_DIGIT_SEPARATOR);
check_subsequent_flags!(INTEGER_LEADING_DIGIT_SEPARATOR, FRACTION_LEADING_DIGIT_SEPARATOR);
check_subsequent_flags!(FRACTION_LEADING_DIGIT_SEPARATOR, EXPONENT_LEADING_DIGIT_SEPARATOR);
check_subsequent_flags!(EXPONENT_LEADING_DIGIT_SEPARATOR, INTEGER_TRAILING_DIGIT_SEPARATOR);
check_subsequent_flags!(INTEGER_TRAILING_DIGIT_SEPARATOR, FRACTION_TRAILING_DIGIT_SEPARATOR);
check_subsequent_flags!(FRACTION_TRAILING_DIGIT_SEPARATOR, EXPONENT_TRAILING_DIGIT_SEPARATOR);
check_subsequent_flags!(EXPONENT_TRAILING_DIGIT_SEPARATOR, INTEGER_CONSECUTIVE_DIGIT_SEPARATOR);
check_subsequent_flags!(INTEGER_CONSECUTIVE_DIGIT_SEPARATOR, FRACTION_CONSECUTIVE_DIGIT_SEPARATOR);
check_subsequent_flags!(FRACTION_CONSECUTIVE_DIGIT_SEPARATOR, EXPONENT_CONSECUTIVE_DIGIT_SEPARATOR);
check_subsequent_flags!(EXPONENT_CONSECUTIVE_DIGIT_SEPARATOR, SPECIAL_DIGIT_SEPARATOR);

// CONTROL CHARACTER & RADIX MASKS
// -------------------------------

/// Shift to convert to and from a digit separator as a `u8`.
pub const DIGIT_SEPARATOR_SHIFT: i32 = 64;

/// Mask to extract the digit separator character.
pub const DIGIT_SEPARATOR: u128 = 0xFF << DIGIT_SEPARATOR_SHIFT;

/// Shift to convert to and from a base prefix as a `u8`.
pub const BASE_PREFIX_SHIFT: i32 = 88;

/// Mask to extract the base prefix character.
pub const BASE_PREFIX: u128 = 0xFF << BASE_PREFIX_SHIFT;

/// Shift to convert to and from a base suffix as a `u8`.
pub const BASE_SUFFIX_SHIFT: i32 = 96;

/// Mask to extract the base suffix character.
pub const BASE_SUFFIX: u128 = 0xFF << BASE_SUFFIX_SHIFT;

/// Shift to convert to and from a mantissa radix as a `u32`.
pub const MANTISSA_RADIX_SHIFT: i32 = 104;

/// Mask to extract the mantissa radix: the radix for the significant digits.
pub const MANTISSA_RADIX: u128 = 0xFF << MANTISSA_RADIX_SHIFT;

/// Alias for `MANTISSA_RADIX_SHIFT`.
pub const RADIX_SHIFT: i32 = MANTISSA_RADIX_SHIFT;

/// Alias for `MANTISSA_RADIX`.
pub const RADIX: u128 = MANTISSA_RADIX;

/// Shift to convert to and from an exponent base as a `u32`.
pub const EXPONENT_BASE_SHIFT: i32 = 112;

/// Mask to extract the exponent base: the base the exponent is raised to.
pub const EXPONENT_BASE: u128 = 0xFF << EXPONENT_BASE_SHIFT;

/// Shift to convert to and from an exponent radix as a `u32`.
pub const EXPONENT_RADIX_SHIFT: i32 = 120;

/// Mask to extract the exponent radix: the radix for the exponent digits.
pub const EXPONENT_RADIX: u128 = 0xFF << EXPONENT_RADIX_SHIFT;

// Masks do not overlap.
check_subsequent_masks!(DIGIT_SEPARATOR, BASE_PREFIX);
check_subsequent_masks!(BASE_PREFIX, BASE_SUFFIX);
check_subsequent_masks!(BASE_SUFFIX, MANTISSA_RADIX);
check_subsequent_masks!(MANTISSA_RADIX, EXPONENT_BASE);
check_subsequent_masks!(EXPONENT_BASE, EXPONENT_RADIX);

// Check all our shifts shift the masks to a single byte.
check_mask_shifts!(DIGIT_SEPARATOR, DIGIT_SEPARATOR_SHIFT);
check_mask_shifts!(BASE_PREFIX, BASE_PREFIX_SHIFT);
check_mask_shifts!(BASE_SUFFIX, BASE_SUFFIX_SHIFT);
check_mask_shifts!(MANTISSA_RADIX, MANTISSA_RADIX_SHIFT);
check_mask_shifts!(EXPONENT_BASE, EXPONENT_BASE_SHIFT);
check_mask_shifts!(EXPONENT_RADIX, EXPONENT_RADIX_SHIFT);

// Check masks don't overlap with neighboring flags.
check_masks_and_flags!(DIGIT_SEPARATOR, SPECIAL_DIGIT_SEPARATOR);

// HIDDEN MASKS
// ------------

/// Mask to extract the flag bits.
#[doc(hidden)]
pub const FLAG_MASK: u128 =
    REQUIRED_DIGITS |
    NO_POSITIVE_MANTISSA_SIGN |
    REQUIRED_MANTISSA_SIGN |
    NO_EXPONENT_NOTATION |
    NO_POSITIVE_EXPONENT_SIGN |
    REQUIRED_EXPONENT_SIGN |
    NO_EXPONENT_WITHOUT_FRACTION |
    NO_SPECIAL |
    CASE_SENSITIVE_SPECIAL |
    NO_INTEGER_LEADING_ZEROS |
    NO_FLOAT_LEADING_ZEROS |
    REQUIRED_EXPONENT_NOTATION |
    CASE_SENSITIVE_EXPONENT |
    CASE_SENSITIVE_BASE_PREFIX |
    CASE_SENSITIVE_BASE_SUFFIX |
    INTERNAL_DIGIT_SEPARATOR |
    LEADING_DIGIT_SEPARATOR |
    TRAILING_DIGIT_SEPARATOR |
    CONSECUTIVE_DIGIT_SEPARATOR |
    SPECIAL_DIGIT_SEPARATOR;

/// Mask to extract the flag bits controlling interface parsing.
///
/// This mask controls all the flags handled by the interface,
/// omitting those that are handled prior. This limits the
/// number of match paths required to determine the correct
/// interface.
#[doc(hidden)]
pub const INTERFACE_FLAG_MASK: u128 =
    REQUIRED_DIGITS |
    NO_EXPONENT_NOTATION |
    NO_POSITIVE_EXPONENT_SIGN |
    REQUIRED_EXPONENT_SIGN |
    NO_EXPONENT_WITHOUT_FRACTION |
    NO_FLOAT_LEADING_ZEROS |
    REQUIRED_EXPONENT_NOTATION |
    INTERNAL_DIGIT_SEPARATOR |
    LEADING_DIGIT_SEPARATOR |
    TRAILING_DIGIT_SEPARATOR |
    CONSECUTIVE_DIGIT_SEPARATOR;

/// Mask to extract digit separator flags.
#[doc(hidden)]
pub const DIGIT_SEPARATOR_FLAG_MASK: u128 =
    INTERNAL_DIGIT_SEPARATOR |
    LEADING_DIGIT_SEPARATOR |
    TRAILING_DIGIT_SEPARATOR |
    CONSECUTIVE_DIGIT_SEPARATOR |
    SPECIAL_DIGIT_SEPARATOR;

/// Mask to extract exponent flags.
#[doc(hidden)]
pub const EXPONENT_FLAG_MASK: u128 =
    REQUIRED_EXPONENT_DIGITS |
    NO_EXPONENT_NOTATION |
    NO_POSITIVE_EXPONENT_SIGN |
    REQUIRED_EXPONENT_SIGN |
    NO_EXPONENT_WITHOUT_FRACTION |
    REQUIRED_EXPONENT_NOTATION |
    EXPONENT_INTERNAL_DIGIT_SEPARATOR |
    EXPONENT_LEADING_DIGIT_SEPARATOR |
    EXPONENT_TRAILING_DIGIT_SEPARATOR |
    EXPONENT_CONSECUTIVE_DIGIT_SEPARATOR;

/// Mask to extract integer digit separator flags.
#[doc(hidden)]
pub const INTEGER_DIGIT_SEPARATOR_FLAG_MASK: u128 =
    INTEGER_INTERNAL_DIGIT_SEPARATOR |
    INTEGER_LEADING_DIGIT_SEPARATOR |
    INTEGER_TRAILING_DIGIT_SEPARATOR |
    INTEGER_CONSECUTIVE_DIGIT_SEPARATOR;

/// Mask to extract fraction digit separator flags.
#[doc(hidden)]
pub const FRACTION_DIGIT_SEPARATOR_FLAG_MASK: u128 =
    FRACTION_INTERNAL_DIGIT_SEPARATOR |
    FRACTION_LEADING_DIGIT_SEPARATOR |
    FRACTION_TRAILING_DIGIT_SEPARATOR |
    FRACTION_CONSECUTIVE_DIGIT_SEPARATOR;

/// Mask to extract exponent digit separator flags.
#[doc(hidden)]
pub const EXPONENT_DIGIT_SEPARATOR_FLAG_MASK: u128 =
    EXPONENT_INTERNAL_DIGIT_SEPARATOR |
    EXPONENT_LEADING_DIGIT_SEPARATOR |
    EXPONENT_TRAILING_DIGIT_SEPARATOR |
    EXPONENT_CONSECUTIVE_DIGIT_SEPARATOR;

// EXTRACTORS
// ----------

/// Extract the digit separator from the format packed struct.
#[inline(always)]
pub const fn digit_separator(format: u128) -> u8 {
    ((format & DIGIT_SEPARATOR) >> DIGIT_SEPARATOR_SHIFT) as u8
}

/// Extract the base prefix character from the format packed struct.
#[inline(always)]
pub const fn base_prefix(format: u128) -> u8 {
    ((format & BASE_PREFIX) >> BASE_PREFIX_SHIFT) as u8
}

/// Extract the base suffix character from the format packed struct.
#[inline(always)]
pub const fn base_suffix(format: u128) -> u8 {
    ((format & BASE_SUFFIX) >> BASE_SUFFIX_SHIFT) as u8
}

/// Extract the mantissa radix from the format packed struct.
#[inline(always)]
pub const fn mantissa_radix(format: u128) -> u32 {
    ((format & MANTISSA_RADIX) >> MANTISSA_RADIX_SHIFT) as u32
}

/// Extract the exponent base from the format packed struct.
/// If not provided, defaults to `mantissa_radix`.
#[inline(always)]
pub const fn exponent_base(format: u128) -> u32 {
    let radix = ((format & EXPONENT_BASE) >> EXPONENT_BASE_SHIFT) as u32;
    if radix == 0 {
        mantissa_radix(format)
    } else {
        radix
    }
}

/// Extract the exponent radix from the format packed struct.
/// If not provided, defaults to `mantissa_radix`.
#[inline(always)]
pub const fn exponent_radix(format: u128) -> u32 {
    let radix = ((format & EXPONENT_RADIX) >> EXPONENT_RADIX_SHIFT) as u32;
    if radix == 0 {
        mantissa_radix(format)
    } else {
        radix
    }
}

/// Extract a generic radix from the format and bitflags.
#[inline(always)]
pub const fn radix_from_flags(format: u128, mask: u128, shift: i32) -> u32 {
    let radix = ((format & mask) >> shift) as u32;
    if radix == 0 {
        mantissa_radix(format)
    } else {
        radix
    }
}

// VALIDATORS
// ----------

// NOTE: All of these are only used when building formats so it doesn't matter if
// they have performance issues, since these will be built at compile time.

/// Determine if the provided exponent flags are valid.
#[inline(always)]
pub const fn is_valid_exponent_flags(format: u128) -> bool {
    // Both cannot be set.
    format & NO_EXPONENT_NOTATION == 0 || format & REQUIRED_EXPONENT_NOTATION == 0
}

/// Determine if an optional control character is valid.
#[inline(always)]
const fn is_valid_optional_control_radix(radix: u32, value: u8) -> bool {
    // Validate the character isn't a digit or sign character, and is valid ASCII.
    use crate::ascii::is_valid_ascii;
    use crate::digit::char_is_digit_const;
    !char_is_digit_const(value, radix) &&
        value != b'+' &&
        value != b'-' &&
        (is_valid_ascii(value) || value == 0)
}

/// Determine if an optional control character is valid.
#[inline(always)]
const fn is_valid_optional_control(format: u128, value: u8) -> bool {
    // Need to get the larger of the two radix values, since these
    // will be the characters that define the valid digits.
    // const fn doesn't support max as of 1.55 nightly.
    let mradix = mantissa_radix(format);
    let eradix = exponent_radix(format);
    let radix = if mradix > eradix {
        mradix
    } else {
        eradix
    };
    is_valid_optional_control_radix(radix, value)
}

/// Determine if an control character is valid.
#[inline(always)]
const fn is_valid_control(format: u128, value: u8) -> bool {
    value != 0 && is_valid_optional_control(format, value)
}

/// Determine if the digit separator is valid.
/// Digit separators must not be valid digits or sign characters.
#[inline(always)]
pub const fn is_valid_digit_separator(format: u128) -> bool {
    let value = digit_separator(format);
    if cfg!(feature = "format") {
        is_valid_optional_control(format, value)
    } else {
        value == 0
    }
}

/// Determine if the base prefix character is valid.
#[inline(always)]
pub const fn is_valid_base_prefix(format: u128) -> bool {
    let value = base_prefix(format);
    if cfg!(feature = "format") {
        is_valid_optional_control(format, value)
    } else {
        value == 0
    }
}

/// Determine if the base suffix character is valid.
#[inline(always)]
pub const fn is_valid_base_suffix(format: u128) -> bool {
    let value = base_suffix(format);
    if cfg!(feature = "format") {
        is_valid_optional_control(format, value)
    } else {
        value == 0
    }
}

/// Determine if all of the "punctuation" characters are valid.
#[inline(always)]
#[allow(clippy::if_same_then_else)] // reason="all are different logic conditions"
pub const fn is_valid_punctuation(format: u128) -> bool {
    // All the checks against optional characters with mandatory are fine:
    // if they're not 0, then they can't overlap, and mandatory can't be 0.
    if cfg!(not(feature = "format")) && digit_separator(format) != 0 {
        // Digit separator set when not allowed.
        false
    } else {
        let separator = digit_separator(format);
        let prefix = base_prefix(format);
        let suffix = base_suffix(format);
        // Check all are optional, or enough are not present.
        match (separator, prefix, suffix) {
            (0, 0, 0) => true,
            (_, 0, 0) => true,
            (0, _, 0) => true,
            (0, 0, _) => true,
            // Can't have more than 1 0, check they're all different.
            (x, y, z) => x != y && x != z && y != z,
        }
    }
}

/// Determine if all of the "punctuation" characters for the options API are valid.
#[inline(always)]
#[allow(clippy::if_same_then_else)] // reason="all are different logic conditions"
#[allow(clippy::needless_bool)] // reason="not needless depending on the format condition"
pub const fn is_valid_options_punctuation(format: u128, exponent: u8, decimal_point: u8) -> bool {
    // All the checks against optional characters with mandatory are fine:
    // if they're not 0, then they can't overlap, and mandatory can't be 0.
    if !is_valid_control(format, decimal_point) || !is_valid_control(format, exponent) {
        // Must be in the valid range.
        false
    } else if decimal_point == exponent {
        // Can't have overlapping characters.
        false
    } else if cfg!(feature = "format") && digit_separator(format) == decimal_point {
        false
    } else if cfg!(feature = "format") && digit_separator(format) == exponent {
        false
    } else if cfg!(feature = "format") && base_prefix(format) == decimal_point {
        false
    } else if cfg!(feature = "format") && base_prefix(format) == exponent {
        false
    } else if cfg!(feature = "format") && base_suffix(format) == decimal_point {
        false
    } else if cfg!(feature = "format") && base_suffix(format) == exponent {
        false
    } else {
        true
    }
}

/// Determine if the radix is valid.
pub const fn is_valid_radix(radix: u32) -> bool {
    if cfg!(feature = "radix") {
        radix >= 2 && radix <= 36
    } else if cfg!(feature = "power-of-two") {
        matches!(radix, 2 | 4 | 8 | 10 | 16 | 32)
    } else {
        radix == 10
    }
}
