#![doc(hidden)]
#[cfg(not(feature = "compact"))]
use lexical_parse_integer::algorithm;
#[cfg(feature = "f16")]
use lexical_util::bf16::bf16;
use lexical_util::digit::{char_to_digit_const, char_to_valid_digit_const};
use lexical_util::error::Error;
#[cfg(feature = "f16")]
use lexical_util::f16::f16;
use lexical_util::format::NumberFormat;
use lexical_util::iterator::{AsBytes, Bytes, DigitsIter, Iter};
use lexical_util::result::Result;
use lexical_util::step::u64_step;
#[cfg(any(feature = "compact", feature = "radix"))]
use crate::bellerophon::bellerophon;
#[cfg(feature = "power-of-two")]
use crate::binary::{binary, slow_binary};
use crate::float::{extended_to_float, ExtendedFloat80, LemireFloat};
#[cfg(not(feature = "compact"))]
use crate::lemire::lemire;
use crate::number::Number;
use crate::options::Options;
use crate::shared;
use crate::slow::slow_radix;
#[cfg(feature = "power-of-two")]
macro_rules! is_power_two {
($radix:expr) => {
matches!($radix, 2 | 4 | 8 | 16 | 32)
};
}
macro_rules! check_radix {
($format:ident) => {{
let format = NumberFormat::<{ $format }> {};
#[cfg(feature = "power-of-two")]
{
if format.radix() != format.exponent_base() {
let valid_radix = matches!(
(format.radix(), format.exponent_base()),
(4, 2) | (8, 2) | (16, 2) | (32, 2) | (16, 4)
);
if !valid_radix {
return Err(Error::InvalidRadix);
}
}
}
#[cfg(not(feature = "power-of-two"))]
{
if format.radix() != format.exponent_base() {
return Err(Error::InvalidRadix);
}
}
}};
}
pub trait ParseFloat: LemireFloat {
#[cfg_attr(not(feature = "compact"), inline(always))]
fn parse_complete<const FORMAT: u128>(bytes: &[u8], options: &Options) -> Result<Self> {
check_radix!(FORMAT);
parse_complete::<Self, FORMAT>(bytes, options)
}
#[cfg_attr(not(feature = "compact"), inline(always))]
fn parse_partial<const FORMAT: u128>(bytes: &[u8], options: &Options) -> Result<(Self, usize)> {
check_radix!(FORMAT);
parse_partial::<Self, FORMAT>(bytes, options)
}
#[cfg_attr(not(feature = "compact"), inline(always))]
fn fast_path_complete<const FORMAT: u128>(bytes: &[u8], options: &Options) -> Result<Self> {
check_radix!(FORMAT);
fast_path_complete::<Self, FORMAT>(bytes, options)
}
#[cfg_attr(not(feature = "compact"), inline(always))]
fn fast_path_partial<const FORMAT: u128>(
bytes: &[u8],
options: &Options,
) -> Result<(Self, usize)> {
check_radix!(FORMAT);
fast_path_partial::<Self, FORMAT>(bytes, options)
}
}
macro_rules! parse_float_impl {
($($t:ty)*) => ($(
impl ParseFloat for $t {}
)*)
}
parse_float_impl! { f32 f64 }
#[cfg(feature = "f16")]
macro_rules! parse_float_as_f32 {
($($t:ty)*) => ($(
impl ParseFloat for $t {
#[cfg_attr(not(feature = "compact"), inline(always))]
fn parse_complete<const FORMAT: u128>(bytes: &[u8], options: &Options)
-> Result<Self>
{
Ok(Self::from_f32(parse_complete::<f32, FORMAT>(bytes, options)?))
}
#[cfg_attr(not(feature = "compact"), inline(always))]
fn parse_partial<const FORMAT: u128>(bytes: &[u8], options: &Options)
-> Result<(Self, usize)>
{
let (float, count) = parse_partial::<f32, FORMAT>(bytes, options)?;
Ok((Self::from_f32(float), count))
}
#[cfg_attr(not(feature = "compact"), inline(always))]
fn fast_path_complete<const FORMAT: u128>(bytes: &[u8], options: &Options)
-> Result<Self>
{
Ok(Self::from_f32(fast_path_complete::<f32, FORMAT>(bytes, options)?))
}
#[cfg_attr(not(feature = "compact"), inline(always))]
fn fast_path_partial<const FORMAT: u128>(bytes: &[u8], options: &Options)
-> Result<(Self, usize)>
{
let (float, count) = fast_path_partial::<f32, FORMAT>(bytes, options)?;
Ok((Self::from_f32(float), count))
}
}
)*)
}
#[cfg(feature = "f16")]
parse_float_as_f32! { bf16 f16 }
#[cfg_attr(not(feature = "compact"), inline(always))]
pub fn parse_mantissa_sign<const FORMAT: u128>(byte: &mut Bytes<'_, FORMAT>) -> Result<bool> {
let format = NumberFormat::<{ FORMAT }> {};
parse_sign!(
byte,
true,
format.no_positive_mantissa_sign(),
format.required_mantissa_sign(),
InvalidPositiveSign,
MissingSign
)
}
#[cfg_attr(not(feature = "compact"), inline(always))]
pub fn parse_exponent_sign<const FORMAT: u128>(byte: &mut Bytes<'_, FORMAT>) -> Result<bool> {
let format = NumberFormat::<{ FORMAT }> {};
parse_sign!(
byte,
true,
format.no_positive_exponent_sign(),
format.required_exponent_sign(),
InvalidPositiveExponentSign,
MissingExponentSign
)
}
macro_rules! parse_number {
(
$format:ident,
$byte:ident,
$is_negative:ident,
$options:ident,
$parse_normal:ident,
$parse_special:ident
) => {{
match $parse_normal::<$format>($byte.clone(), $is_negative, $options) {
Ok(n) => n,
Err(e) => {
if let Some(value) =
$parse_special::<_, $format>($byte.clone(), $is_negative, $options)
{
return Ok(value);
} else {
return Err(e);
}
},
}
}};
}
macro_rules! to_native {
($type:ident, $fp:ident, $is_negative:ident) => {{
let mut float = extended_to_float::<$type>($fp);
if $is_negative {
float = -float;
}
float
}};
}
#[allow(clippy::missing_inline_in_public_items)] pub fn parse_complete<F: LemireFloat, const FORMAT: u128>(
bytes: &[u8],
options: &Options,
) -> Result<F> {
let mut byte = bytes.bytes::<{ FORMAT }>();
let is_negative = parse_mantissa_sign(&mut byte)?;
if byte.integer_iter().is_consumed() {
if NumberFormat::<FORMAT>::REQUIRED_INTEGER_DIGITS
|| NumberFormat::<FORMAT>::REQUIRED_MANTISSA_DIGITS
{
return Err(Error::Empty(byte.cursor()));
} else {
return Ok(F::ZERO);
}
}
let num: Number<'_> =
parse_number!(FORMAT, byte, is_negative, options, parse_complete_number, parse_special);
if let Some(value) = num.try_fast_path::<_, FORMAT>() {
return Ok(value);
}
let mut fp = moderate_path::<F, FORMAT>(&num, options.lossy());
if fp.exp < 0 {
debug_assert!(!options.lossy(), "lossy algorithms never use slow algorithms");
fp.exp -= shared::INVALID_FP;
fp = slow_path::<F, FORMAT>(num, fp);
}
Ok(to_native!(F, fp, is_negative))
}
#[allow(clippy::missing_inline_in_public_items)] pub fn fast_path_complete<F: LemireFloat, const FORMAT: u128>(
bytes: &[u8],
options: &Options,
) -> Result<F> {
let mut byte = bytes.bytes::<{ FORMAT }>();
let is_negative = parse_mantissa_sign(&mut byte)?;
if byte.integer_iter().is_consumed() {
if NumberFormat::<FORMAT>::REQUIRED_INTEGER_DIGITS
|| NumberFormat::<FORMAT>::REQUIRED_MANTISSA_DIGITS
{
return Err(Error::Empty(byte.cursor()));
} else {
return Ok(F::ZERO);
}
}
let num =
parse_number!(FORMAT, byte, is_negative, options, parse_complete_number, parse_special);
Ok(num.force_fast_path::<_, FORMAT>())
}
#[allow(clippy::missing_inline_in_public_items)] pub fn parse_partial<F: LemireFloat, const FORMAT: u128>(
bytes: &[u8],
options: &Options,
) -> Result<(F, usize)> {
let mut byte = bytes.bytes::<{ FORMAT }>();
let is_negative = parse_mantissa_sign(&mut byte)?;
if byte.integer_iter().is_consumed() {
if NumberFormat::<FORMAT>::REQUIRED_INTEGER_DIGITS
|| NumberFormat::<FORMAT>::REQUIRED_MANTISSA_DIGITS
{
return Err(Error::Empty(byte.cursor()));
} else {
return Ok((F::ZERO, byte.cursor()));
}
}
let (num, count) = parse_number!(
FORMAT,
byte,
is_negative,
options,
parse_partial_number,
parse_partial_special
);
if let Some(value) = num.try_fast_path::<_, FORMAT>() {
return Ok((value, count));
}
let mut fp = moderate_path::<F, FORMAT>(&num, options.lossy());
if fp.exp < 0 {
debug_assert!(!options.lossy(), "lossy algorithms never use slow algorithms");
fp.exp -= shared::INVALID_FP;
fp = slow_path::<F, FORMAT>(num, fp);
}
Ok((to_native!(F, fp, is_negative), count))
}
#[allow(clippy::missing_inline_in_public_items)] pub fn fast_path_partial<F: LemireFloat, const FORMAT: u128>(
bytes: &[u8],
options: &Options,
) -> Result<(F, usize)> {
let mut byte = bytes.bytes::<{ FORMAT }>();
let is_negative = parse_mantissa_sign(&mut byte)?;
if byte.integer_iter().is_consumed() {
if NumberFormat::<FORMAT>::REQUIRED_INTEGER_DIGITS
|| NumberFormat::<FORMAT>::REQUIRED_MANTISSA_DIGITS
{
return Err(Error::Empty(byte.cursor()));
} else {
return Ok((F::ZERO, byte.cursor()));
}
}
let (num, count) = parse_number!(
FORMAT,
byte,
is_negative,
options,
parse_partial_number,
parse_partial_special
);
Ok((num.force_fast_path::<_, FORMAT>(), count))
}
#[must_use]
#[inline(always)]
pub fn moderate_path<F: LemireFloat, const FORMAT: u128>(
num: &Number,
lossy: bool,
) -> ExtendedFloat80 {
#[cfg(feature = "compact")]
{
#[cfg(feature = "power-of-two")]
{
let format = NumberFormat::<{ FORMAT }> {};
if is_power_two!(format.mantissa_radix()) {
binary::<F, FORMAT>(num, lossy)
} else {
bellerophon::<F, FORMAT>(num, lossy)
}
}
#[cfg(not(feature = "power-of-two"))]
{
bellerophon::<F, FORMAT>(num, lossy)
}
}
#[cfg(not(feature = "compact"))]
{
#[cfg(feature = "radix")]
{
let format = NumberFormat::<{ FORMAT }> {};
let radix = format.mantissa_radix();
if radix == 10 {
lemire::<F>(num, lossy)
} else if is_power_two!(radix) {
binary::<F, FORMAT>(num, lossy)
} else {
bellerophon::<F, FORMAT>(num, lossy)
}
}
#[cfg(all(feature = "power-of-two", not(feature = "radix")))]
{
let format = NumberFormat::<{ FORMAT }> {};
let radix = format.mantissa_radix();
debug_assert!(matches!(radix, 2 | 4 | 8 | 10 | 16 | 32));
if radix == 10 {
lemire::<F>(num, lossy)
} else {
binary::<F, FORMAT>(num, lossy)
}
}
#[cfg(not(feature = "power-of-two"))]
{
lemire::<F>(num, lossy)
}
}
}
#[must_use]
#[inline(always)]
pub fn slow_path<F: LemireFloat, const FORMAT: u128>(
num: Number,
fp: ExtendedFloat80,
) -> ExtendedFloat80 {
#[cfg(not(feature = "power-of-two"))]
{
slow_radix::<F, FORMAT>(num, fp)
}
#[cfg(feature = "power-of-two")]
{
let format = NumberFormat::<{ FORMAT }> {};
if is_power_two!(format.mantissa_radix()) {
slow_binary::<F, FORMAT>(num)
} else {
slow_radix::<F, FORMAT>(num, fp)
}
}
}
#[cfg_attr(not(feature = "compact"), inline(always))]
#[allow(unused_mut)] #[allow(clippy::unwrap_used)] #[allow(clippy::collapsible_if)] #[allow(clippy::cast_possible_wrap)] #[allow(clippy::too_many_lines)] pub fn parse_number<'a, const FORMAT: u128, const IS_PARTIAL: bool>(
mut byte: Bytes<'a, FORMAT>,
is_negative: bool,
options: &Options,
) -> Result<(Number<'a>, usize)> {
let format = NumberFormat::<{ FORMAT }> {};
let decimal_point = options.decimal_point();
let exponent_character = options.exponent();
debug_assert!(format.is_valid(), "should have already checked for an invalid number format");
debug_assert!(!byte.is_buffer_empty(), "should have previously checked for empty input");
let bits_per_digit = shared::log2(format.mantissa_radix()) as i64;
let bits_per_base = shared::log2(format.exponent_base()) as i64;
#[allow(unused_variables)]
let mut is_prefix = false;
#[cfg(feature = "format")]
{
let base_prefix = format.base_prefix();
let mut iter = byte.integer_iter();
if base_prefix != 0 && iter.read_if_value_cased(b'0').is_some() {
is_prefix = true;
if iter.read_if_value(base_prefix, format.case_sensitive_base_prefix()).is_some()
&& iter.is_buffer_empty()
&& format.required_integer_digits()
{
return Err(Error::EmptyInteger(iter.cursor()));
}
}
}
let mut mantissa = 0_u64;
let start = byte.clone();
#[cfg(not(feature = "compact"))]
parse_8digits::<_, FORMAT>(byte.integer_iter(), &mut mantissa);
parse_digits::<_, _, FORMAT>(byte.integer_iter(), |digit| {
mantissa = mantissa.wrapping_mul(format.radix() as u64).wrapping_add(digit as u64);
});
let mut n_digits = byte.current_count() - start.current_count();
#[cfg(feature = "format")]
if format.required_integer_digits() && n_digits == 0 {
return Err(Error::EmptyInteger(byte.cursor()));
}
let b_digits = if cfg!(feature = "format") && !byte.integer_iter().is_contiguous() {
byte.cursor() - start.cursor()
} else {
n_digits
};
debug_assert!(
b_digits <= start.as_slice().len(),
"number of digits parsed must <= buffer length"
);
let integer_digits = unsafe { start.as_slice().get_unchecked(..b_digits) };
#[cfg(feature = "format")]
if !is_prefix && format.no_float_leading_zeros() {
if integer_digits.len() > 1 && integer_digits.first() == Some(&b'0') {
return Err(Error::InvalidLeadingZeros(start.cursor()));
}
}
let mut n_after_dot = 0;
let mut exponent = 0_i64;
let mut implicit_exponent: i64;
let int_end = n_digits as i64;
let mut fraction_digits = None;
let has_decimal = byte.first_is_cased(decimal_point);
if has_decimal {
unsafe { byte.step_unchecked() };
let before = byte.clone();
#[cfg(not(feature = "compact"))]
parse_8digits::<_, FORMAT>(byte.fraction_iter(), &mut mantissa);
parse_digits::<_, _, FORMAT>(byte.fraction_iter(), |digit| {
mantissa = mantissa.wrapping_mul(format.radix() as u64).wrapping_add(digit as u64);
});
n_after_dot = byte.current_count() - before.current_count();
let b_after_dot = if cfg!(feature = "format") && !byte.fraction_iter().is_contiguous() {
byte.cursor() - before.cursor()
} else {
n_after_dot
};
debug_assert!(
b_after_dot <= before.as_slice().len(),
"digits after dot must be smaller than buffer"
);
fraction_digits = Some(unsafe { before.as_slice().get_unchecked(..b_after_dot) });
implicit_exponent = -(n_after_dot as i64);
if format.mantissa_radix() == format.exponent_base() {
exponent = implicit_exponent;
} else {
debug_assert!(bits_per_digit % bits_per_base == 0, "exponent must be a power of base");
exponent = implicit_exponent * bits_per_digit / bits_per_base;
};
#[cfg(feature = "format")]
if format.required_fraction_digits() && n_after_dot == 0 {
return Err(Error::EmptyFraction(byte.cursor()));
}
}
let has_exponent = byte
.first_is(exponent_character, format.case_sensitive_exponent() && cfg!(feature = "format"));
n_digits += n_after_dot;
if format.required_mantissa_digits()
&& (n_digits == 0 || (cfg!(feature = "format") && byte.current_count() == 0))
{
let any_digits = start.clone().integer_iter().peek().is_some();
if has_decimal || has_exponent || !any_digits || IS_PARTIAL {
return Err(Error::EmptyMantissa(byte.cursor()));
} else {
return Err(Error::InvalidDigit(start.cursor()));
}
}
let mut explicit_exponent = 0_i64;
if has_exponent {
unsafe { byte.step_unchecked() };
#[cfg(feature = "format")]
{
if format.no_exponent_notation() {
return Err(Error::InvalidExponent(byte.cursor() - 1));
}
if format.no_exponent_without_fraction() && fraction_digits.is_none() {
return Err(Error::ExponentWithoutFraction(byte.cursor() - 1));
}
}
let is_negative_exponent = parse_exponent_sign(&mut byte)?;
let before = byte.current_count();
parse_digits::<_, _, FORMAT>(byte.exponent_iter(), |digit| {
if explicit_exponent < 0x10000000 {
explicit_exponent *= format.radix() as i64;
explicit_exponent += digit as i64;
}
});
if format.required_exponent_digits() && byte.current_count() - before == 0 {
return Err(Error::EmptyExponent(byte.cursor()));
}
explicit_exponent = if is_negative_exponent {
-explicit_exponent
} else {
explicit_exponent
};
exponent += explicit_exponent;
} else if cfg!(feature = "format") && format.required_exponent_notation() {
return Err(Error::MissingExponent(byte.cursor()));
}
#[allow(unused_variables)]
let base_suffix = format.base_suffix();
#[cfg(feature = "format")]
if base_suffix != 0 {
if byte.first_is(base_suffix, format.case_sensitive_base_suffix()) {
unsafe { byte.step_unchecked() };
}
}
let end = byte.cursor();
let mut step = u64_step(format.radix());
let mut many_digits = false;
#[cfg(feature = "format")]
if !format.required_mantissa_digits() && n_digits == 0 {
exponent = 0;
}
if n_digits <= step {
return Ok((
Number {
exponent,
mantissa,
is_negative,
many_digits: false,
integer: integer_digits,
fraction: fraction_digits,
},
end,
));
}
n_digits -= step;
let mut zeros = start.clone();
let mut zeros_integer = zeros.integer_iter();
n_digits = n_digits.saturating_sub(zeros_integer.skip_zeros());
if zeros.first_is_cased(decimal_point) {
unsafe { zeros.step_unchecked() };
}
let mut zeros_fraction = zeros.fraction_iter();
n_digits = n_digits.saturating_sub(zeros_fraction.skip_zeros());
if n_digits > 0 {
many_digits = true;
mantissa = 0;
let mut integer = integer_digits.bytes::<{ FORMAT }>();
let mut integer_iter = integer.integer_iter();
integer_iter.skip_zeros();
parse_u64_digits::<_, FORMAT>(integer_iter, &mut mantissa, &mut step);
implicit_exponent = if step == 0
|| (cfg!(feature = "format") && !byte.is_contiguous() && fraction_digits.is_none())
{
int_end - integer.current_count() as i64
} else {
let mut fraction = fraction_digits.unwrap().bytes::<{ FORMAT }>();
let mut fraction_iter = fraction.fraction_iter();
if mantissa == 0 {
fraction_iter.skip_zeros();
}
parse_u64_digits::<_, FORMAT>(fraction_iter, &mut mantissa, &mut step);
-(fraction.current_count() as i64)
};
if format.mantissa_radix() == format.exponent_base() {
exponent = implicit_exponent;
} else {
debug_assert!(bits_per_digit % bits_per_base == 0, "exponent must be a power of base");
exponent = implicit_exponent * bits_per_digit / bits_per_base;
};
exponent += explicit_exponent;
}
Ok((
Number {
exponent,
mantissa,
is_negative,
many_digits,
integer: integer_digits,
fraction: fraction_digits,
},
end,
))
}
pub fn parse_partial_number<'a, const FORMAT: u128>(
byte: Bytes<'a, FORMAT>,
is_negative: bool,
options: &Options,
) -> Result<(Number<'a>, usize)> {
parse_number::<FORMAT, true>(byte, is_negative, options)
}
#[inline(always)]
pub fn parse_complete_number<'a, const FORMAT: u128>(
byte: Bytes<'a, FORMAT>,
is_negative: bool,
options: &Options,
) -> Result<Number<'a>> {
let length = byte.buffer_length();
let (float, count) = parse_number::<FORMAT, false>(byte, is_negative, options)?;
if count == length {
Ok(float)
} else {
Err(Error::InvalidDigit(count))
}
}
#[inline(always)]
pub fn parse_digits<'a, Iter, Cb, const FORMAT: u128>(mut iter: Iter, mut cb: Cb)
where
Iter: DigitsIter<'a>,
Cb: FnMut(u32),
{
let format = NumberFormat::<{ FORMAT }> {};
let radix = format.radix();
while let Some(&c) = iter.peek() {
match char_to_digit_const(c, radix) {
Some(v) => cb(v),
None => break,
}
unsafe { iter.step_unchecked() };
iter.increment_count();
}
}
#[inline(always)]
#[cfg(not(feature = "compact"))]
pub fn parse_8digits<'a, Iter, const FORMAT: u128>(mut iter: Iter, mantissa: &mut u64)
where
Iter: DigitsIter<'a>,
{
let format = NumberFormat::<{ FORMAT }> {};
let radix: u64 = format.radix() as u64;
if can_try_parse_multidigit!(iter, radix) {
debug_assert!(radix < 16, "radices over 16 will overflow with radix^8");
let radix8 = format.radix8() as u64;
while let Some(v) = algorithm::try_parse_8digits::<u64, _, FORMAT>(&mut iter) {
*mantissa = mantissa.wrapping_mul(radix8).wrapping_add(v);
}
}
}
#[cfg_attr(not(feature = "compact"), inline(always))]
pub fn parse_u64_digits<'a, Iter, const FORMAT: u128>(
mut iter: Iter,
mantissa: &mut u64,
step: &mut usize,
) where
Iter: DigitsIter<'a>,
{
let format = NumberFormat::<{ FORMAT }> {};
let radix = format.radix() as u64;
#[cfg(not(feature = "compact"))]
if can_try_parse_multidigit!(iter, radix) {
debug_assert!(radix < 16, "radices over 16 will overflow with radix^8");
let radix8 = format.radix8() as u64;
while *step > 8 {
if let Some(v) = algorithm::try_parse_8digits::<u64, _, FORMAT>(&mut iter) {
*mantissa = mantissa.wrapping_mul(radix8).wrapping_add(v);
*step -= 8;
} else {
break;
}
}
}
while let Some(&c) = iter.peek() {
if *step > 0 {
let digit = char_to_valid_digit_const(c, radix as u32);
*mantissa = *mantissa * radix + digit as u64;
*step -= 1;
unsafe { iter.step_unchecked() };
iter.increment_count();
} else {
break;
}
}
}
#[must_use]
#[inline(always)]
pub fn is_special_eq<const FORMAT: u128>(mut byte: Bytes<FORMAT>, string: &'static [u8]) -> usize {
let format = NumberFormat::<{ FORMAT }> {};
if cfg!(feature = "format") && format.case_sensitive_special() {
if shared::starts_with(byte.special_iter(), string.iter()) {
byte.special_iter().peek();
return byte.cursor();
}
} else if shared::starts_with_uncased(byte.special_iter(), string.iter()) {
byte.special_iter().peek();
return byte.cursor();
}
0
}
#[must_use]
#[cfg_attr(not(feature = "compact"), inline(always))]
pub fn parse_positive_special<F, const FORMAT: u128>(
byte: Bytes<FORMAT>,
options: &Options,
) -> Option<(F, usize)>
where
F: LemireFloat,
{
let format = NumberFormat::<{ FORMAT }> {};
if cfg!(feature = "format") && format.no_special() {
return None;
}
let cursor = byte.cursor();
let length = byte.buffer_length() - cursor;
if let Some(nan_string) = options.nan_string() {
if length >= nan_string.len() {
let count = is_special_eq::<FORMAT>(byte.clone(), nan_string);
if count != 0 {
return Some((F::NAN, count));
}
}
}
if let Some(infinity_string) = options.infinity_string() {
if length >= infinity_string.len() {
let count = is_special_eq::<FORMAT>(byte.clone(), infinity_string);
if count != 0 {
return Some((F::INFINITY, count));
}
}
}
if let Some(inf_string) = options.inf_string() {
if length >= inf_string.len() {
let count = is_special_eq::<FORMAT>(byte.clone(), inf_string);
if count != 0 {
return Some((F::INFINITY, count));
}
}
}
None
}
#[must_use]
#[inline(always)]
pub fn parse_partial_special<F, const FORMAT: u128>(
byte: Bytes<FORMAT>,
is_negative: bool,
options: &Options,
) -> Option<(F, usize)>
where
F: LemireFloat,
{
let (mut float, count) = parse_positive_special::<F, FORMAT>(byte, options)?;
if is_negative {
float = -float;
}
Some((float, count))
}
#[must_use]
#[inline(always)]
pub fn parse_special<F, const FORMAT: u128>(
byte: Bytes<FORMAT>,
is_negative: bool,
options: &Options,
) -> Option<F>
where
F: LemireFloat,
{
let length = byte.buffer_length();
if let Some((float, count)) = parse_partial_special::<F, FORMAT>(byte, is_negative, options) {
if count == length {
return Some(float);
}
}
None
}