#![cfg_attr(rustfmt, rustfmt::skip)]
use static_assertions::const_assert;
macro_rules! check_subsequent_flags {
($x:ident, $y:ident) => {
const_assert!($x << 1 == $y);
};
}
macro_rules! check_subsequent_masks {
($x:ident, $y:ident) => {
const_assert!($x & $y == 0);
};
}
macro_rules! check_mask_shifts {
($mask:ident, $shift:ident) => {
const_assert!(0 < $mask >> $shift && 255 >= $mask >> $shift);
};
}
macro_rules! check_masks_and_flags {
($x:ident, $y:ident) => {
const_assert!($x & $y == 0);
};
}
pub const REQUIRED_INTEGER_DIGITS: u128 = 1 << 0;
pub const REQUIRED_FRACTION_DIGITS: u128 = 1 << 1;
pub const REQUIRED_EXPONENT_DIGITS: u128 = 1 << 2;
pub const REQUIRED_MANTISSA_DIGITS: u128 = 1 << 3;
pub const REQUIRED_DIGITS: u128 =
REQUIRED_INTEGER_DIGITS |
REQUIRED_FRACTION_DIGITS |
REQUIRED_EXPONENT_DIGITS |
REQUIRED_MANTISSA_DIGITS;
pub const NO_POSITIVE_MANTISSA_SIGN: u128 = 1 << 4;
pub const REQUIRED_MANTISSA_SIGN: u128 = 1 << 5;
pub const NO_EXPONENT_NOTATION: u128 = 1 << 6;
pub const NO_POSITIVE_EXPONENT_SIGN: u128 = 1 << 7;
pub const REQUIRED_EXPONENT_SIGN: u128 = 1 << 8;
pub const NO_EXPONENT_WITHOUT_FRACTION: u128 = 1 << 9;
pub const NO_SPECIAL: u128 = 1 << 10;
pub const CASE_SENSITIVE_SPECIAL: u128 = 1 << 11;
pub const NO_INTEGER_LEADING_ZEROS: u128 = 1 << 12;
pub const NO_FLOAT_LEADING_ZEROS: u128 = 1 << 13;
pub const REQUIRED_EXPONENT_NOTATION: u128 = 1 << 14;
pub const CASE_SENSITIVE_EXPONENT: u128 = 1 << 15;
pub const CASE_SENSITIVE_BASE_PREFIX: u128 = 1 << 16;
pub const CASE_SENSITIVE_BASE_SUFFIX: u128 = 1 << 17;
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);
pub const INTEGER_INTERNAL_DIGIT_SEPARATOR: u128 = 1 << 32;
pub const FRACTION_INTERNAL_DIGIT_SEPARATOR: u128 = 1 << 33;
pub const EXPONENT_INTERNAL_DIGIT_SEPARATOR: u128 = 1 << 34;
pub const INTEGER_LEADING_DIGIT_SEPARATOR: u128 = 1 << 35;
pub const FRACTION_LEADING_DIGIT_SEPARATOR: u128 = 1 << 36;
pub const EXPONENT_LEADING_DIGIT_SEPARATOR: u128 = 1 << 37;
pub const INTEGER_TRAILING_DIGIT_SEPARATOR: u128 = 1 << 38;
pub const FRACTION_TRAILING_DIGIT_SEPARATOR: u128 = 1 << 39;
pub const EXPONENT_TRAILING_DIGIT_SEPARATOR: u128 = 1 << 40;
pub const INTEGER_CONSECUTIVE_DIGIT_SEPARATOR: u128 = 1 << 41;
pub const FRACTION_CONSECUTIVE_DIGIT_SEPARATOR: u128 = 1 << 42;
pub const EXPONENT_CONSECUTIVE_DIGIT_SEPARATOR: u128 = 1 << 43;
pub const INTERNAL_DIGIT_SEPARATOR: u128 =
INTEGER_INTERNAL_DIGIT_SEPARATOR |
FRACTION_INTERNAL_DIGIT_SEPARATOR |
EXPONENT_INTERNAL_DIGIT_SEPARATOR;
pub const LEADING_DIGIT_SEPARATOR: u128 =
INTEGER_LEADING_DIGIT_SEPARATOR |
FRACTION_LEADING_DIGIT_SEPARATOR |
EXPONENT_LEADING_DIGIT_SEPARATOR;
pub const TRAILING_DIGIT_SEPARATOR: u128 =
INTEGER_TRAILING_DIGIT_SEPARATOR |
FRACTION_TRAILING_DIGIT_SEPARATOR |
EXPONENT_TRAILING_DIGIT_SEPARATOR;
pub const CONSECUTIVE_DIGIT_SEPARATOR: u128 =
INTEGER_CONSECUTIVE_DIGIT_SEPARATOR |
FRACTION_CONSECUTIVE_DIGIT_SEPARATOR |
EXPONENT_CONSECUTIVE_DIGIT_SEPARATOR;
pub const SPECIAL_DIGIT_SEPARATOR: u128 = 1 << 44;
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);
pub const DIGIT_SEPARATOR_SHIFT: i32 = 64;
pub const DIGIT_SEPARATOR: u128 = 0xFF << DIGIT_SEPARATOR_SHIFT;
pub const BASE_PREFIX_SHIFT: i32 = 88;
pub const BASE_PREFIX: u128 = 0xFF << BASE_PREFIX_SHIFT;
pub const BASE_SUFFIX_SHIFT: i32 = 96;
pub const BASE_SUFFIX: u128 = 0xFF << BASE_SUFFIX_SHIFT;
pub const MANTISSA_RADIX_SHIFT: i32 = 104;
pub const MANTISSA_RADIX: u128 = 0xFF << MANTISSA_RADIX_SHIFT;
pub const RADIX_SHIFT: i32 = MANTISSA_RADIX_SHIFT;
pub const RADIX: u128 = MANTISSA_RADIX;
pub const EXPONENT_BASE_SHIFT: i32 = 112;
pub const EXPONENT_BASE: u128 = 0xFF << EXPONENT_BASE_SHIFT;
pub const EXPONENT_RADIX_SHIFT: i32 = 120;
pub const EXPONENT_RADIX: u128 = 0xFF << EXPONENT_RADIX_SHIFT;
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_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_and_flags!(DIGIT_SEPARATOR, SPECIAL_DIGIT_SEPARATOR);
#[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;
#[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;
#[doc(hidden)]
pub const DIGIT_SEPARATOR_FLAG_MASK: u128 =
INTERNAL_DIGIT_SEPARATOR |
LEADING_DIGIT_SEPARATOR |
TRAILING_DIGIT_SEPARATOR |
CONSECUTIVE_DIGIT_SEPARATOR |
SPECIAL_DIGIT_SEPARATOR;
#[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;
#[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;
#[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;
#[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;
#[inline]
pub const fn digit_separator(format: u128) -> u8 {
((format & DIGIT_SEPARATOR) >> DIGIT_SEPARATOR_SHIFT) as u8
}
#[inline]
pub const fn base_prefix(format: u128) -> u8 {
((format & BASE_PREFIX) >> BASE_PREFIX_SHIFT) as u8
}
#[inline]
pub const fn base_suffix(format: u128) -> u8 {
((format & BASE_SUFFIX) >> BASE_SUFFIX_SHIFT) as u8
}
#[inline]
pub const fn mantissa_radix(format: u128) -> u32 {
((format & MANTISSA_RADIX) >> MANTISSA_RADIX_SHIFT) as u32
}
#[inline]
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
}
}
#[inline]
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
}
}
#[inline]
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
}
}
#[inline]
pub const fn is_valid_exponent_flags(format: u128) -> bool {
format & NO_EXPONENT_NOTATION == 0 || format & REQUIRED_EXPONENT_NOTATION == 0
}
#[inline]
const fn is_valid_optional_control_radix(radix: u32, value: u8) -> bool {
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)
}
#[inline]
const fn is_valid_optional_control(format: u128, value: u8) -> bool {
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)
}
#[inline]
const fn is_valid_control(format: u128, value: u8) -> bool {
value != 0 && is_valid_optional_control(format, value)
}
#[inline]
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
}
}
#[inline]
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
}
}
#[inline]
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
}
}
#[inline]
#[allow(clippy::if_same_then_else)]
pub const fn is_valid_punctuation(format: u128) -> bool {
if cfg!(not(feature = "format")) && digit_separator(format) != 0 {
false
} else {
let separator = digit_separator(format);
let prefix = base_prefix(format);
let suffix = base_suffix(format);
match (separator, prefix, suffix) {
(0, 0, 0) => true,
(_, 0, 0) => true,
(0, _, 0) => true,
(0, 0, _) => true,
(x, y, z) => x != y && x != z && y != z,
}
}
}
#[inline]
#[allow(clippy::if_same_then_else, clippy::needless_bool)]
pub const fn is_valid_options_punctuation(format: u128, exponent: u8, decimal_point: u8) -> bool {
if !is_valid_control(format, decimal_point) || !is_valid_control(format, exponent) {
false
} else if decimal_point == exponent {
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
}
}
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
}
}