diff --git a/src/number/complete.rs b/src/number/complete.rs index 2592ff4cb..d23079e76 100644 --- a/src/number/complete.rs +++ b/src/number/complete.rs @@ -1426,6 +1426,40 @@ where )(input) } +// workaround until issues with minimal-lexical are fixed +#[doc(hidden)] +pub fn recognize_float_or_exceptions>(input: T) -> IResult +where + T: Slice> + Slice>, + T: Clone + Offset, + T: InputIter + InputTake + Compare<&'static str>, + ::Item: AsChar, + T: InputTakeAtPosition, + ::Item: AsChar, +{ + alt(( + |i: T| { + recognize_float::<_, E>(i.clone()).map_err(|e| match e { + crate::Err::Error(_) => crate::Err::Error(E::from_error_kind(i, ErrorKind::Float)), + crate::Err::Failure(_) => crate::Err::Failure(E::from_error_kind(i, ErrorKind::Float)), + crate::Err::Incomplete(needed) => crate::Err::Incomplete(needed), + }) + }, + |i: T| { + crate::bytes::complete::tag_no_case::<_, _, E>("nan")(i.clone()) + .map_err(|_| crate::Err::Error(E::from_error_kind(i, ErrorKind::Float))) + }, + |i: T| { + crate::bytes::complete::tag_no_case::<_, _, E>("inf")(i.clone()) + .map_err(|_| crate::Err::Error(E::from_error_kind(i, ErrorKind::Float))) + }, + |i: T| { + crate::bytes::complete::tag_no_case::<_, _, E>("infinity")(i.clone()) + .map_err(|_| crate::Err::Error(E::from_error_kind(i, ErrorKind::Float))) + }, + ))(input) +} + /// Recognizes a floating point number in text format and returns the integer, fraction and exponent parts of the input data /// /// *Complete version*: Can parse until the end of input. @@ -1517,6 +1551,8 @@ where Ok((i, (sign, integer, fraction, exp))) } +use crate::traits::ParseTo; + /// Recognizes floating point number in text format and returns a f32. /// /// *Complete version*: Can parse until the end of input. @@ -1537,7 +1573,7 @@ where pub fn float>(input: T) -> IResult where T: Slice> + Slice> + Slice>, - T: Clone + Offset, + T: Clone + Offset + ParseTo + Compare<&'static str>, T: InputIter + InputLength + InputTake, ::Item: AsChar + Copy, ::IterElem: Clone, @@ -1546,6 +1582,7 @@ where T: AsBytes, T: for<'a> Compare<&'a [u8]>, { + /* let (i, (sign, integer, fraction, exponent)) = recognize_float_parts(input)?; let mut float: f32 = minimal_lexical::parse_float( @@ -1558,6 +1595,15 @@ where } Ok((i, float)) + */ + let (i, s) = recognize_float_or_exceptions(input)?; + match s.parse_to() { + Some(f) => (Ok((i, f))), + None => Err(crate::Err::Error(E::from_error_kind( + i, + crate::error::ErrorKind::Float, + ))), + } } /// Recognizes floating point number in text format and returns a f64. @@ -1580,7 +1626,7 @@ where pub fn double>(input: T) -> IResult where T: Slice> + Slice> + Slice>, - T: Clone + Offset, + T: Clone + Offset + ParseTo + Compare<&'static str>, T: InputIter + InputLength + InputTake, ::Item: AsChar + Copy, ::IterElem: Clone, @@ -1589,6 +1635,7 @@ where T: AsBytes, T: for<'a> Compare<&'a [u8]>, { + /* let (i, (sign, integer, fraction, exponent)) = recognize_float_parts(input)?; let mut float: f64 = minimal_lexical::parse_float( @@ -1601,6 +1648,15 @@ where } Ok((i, float)) + */ + let (i, s) = recognize_float_or_exceptions(input)?; + match s.parse_to() { + Some(f) => (Ok((i, f))), + None => Err(crate::Err::Error(E::from_error_kind( + i, + crate::error::ErrorKind::Float, + ))), + } } #[cfg(test)] @@ -1941,6 +1997,7 @@ mod tests { "12.34", "-1.234E-12", "-1.234e-12", + "0.00000000000000000087", ]; for test in test_cases.drain(..) { @@ -1964,6 +2021,14 @@ mod tests { recognize_float(remaining_exponent), Err(Err::Failure(("", ErrorKind::Digit))) ); + + let (_i, nan) = float::<_, ()>("NaN").unwrap(); + assert!(nan.is_nan()); + + let (_i, inf) = float::<_, ()>("inf").unwrap(); + assert!(inf.is_infinite()); + let (_i, inf) = float::<_, ()>("infinite").unwrap(); + assert!(inf.is_infinite()); } #[test] @@ -2051,7 +2116,6 @@ mod tests { #[cfg(feature = "std")] fn parse_f64(i: &str) -> IResult<&str, f64, ()> { - use crate::traits::ParseTo; match recognize_float(i) { Err(e) => Err(e), Ok((i, s)) => { diff --git a/src/number/streaming.rs b/src/number/streaming.rs index d2d0f3ca9..7c53ccc47 100644 --- a/src/number/streaming.rs +++ b/src/number/streaming.rs @@ -1395,6 +1395,40 @@ where )(input) } +// workaround until issues with minimal-lexical are fixed +#[doc(hidden)] +pub fn recognize_float_or_exceptions>(input: T) -> IResult +where + T: Slice> + Slice>, + T: Clone + Offset, + T: InputIter + InputTake + InputLength + Compare<&'static str>, + ::Item: AsChar, + T: InputTakeAtPosition, + ::Item: AsChar, +{ + alt(( + |i: T| { + recognize_float::<_, E>(i.clone()).map_err(|e| match e { + crate::Err::Error(_) => crate::Err::Error(E::from_error_kind(i, ErrorKind::Float)), + crate::Err::Failure(_) => crate::Err::Failure(E::from_error_kind(i, ErrorKind::Float)), + crate::Err::Incomplete(needed) => crate::Err::Incomplete(needed), + }) + }, + |i: T| { + crate::bytes::streaming::tag_no_case::<_, _, E>("nan")(i.clone()) + .map_err(|_| crate::Err::Error(E::from_error_kind(i, ErrorKind::Float))) + }, + |i: T| { + crate::bytes::streaming::tag_no_case::<_, _, E>("inf")(i.clone()) + .map_err(|_| crate::Err::Error(E::from_error_kind(i, ErrorKind::Float))) + }, + |i: T| { + crate::bytes::streaming::tag_no_case::<_, _, E>("infinity")(i.clone()) + .map_err(|_| crate::Err::Error(E::from_error_kind(i, ErrorKind::Float))) + }, + ))(input) +} + /// Recognizes a floating point number in text format and returns the integer, fraction and exponent parts of the input data /// /// *Streaming version*: Will return `Err(nom::Err::Incomplete(_))` if there is not enough data. @@ -1512,7 +1546,7 @@ pub fn float>(input: T) -> IResult where T: Slice> + Slice>, T: Clone + Offset, - T: InputIter + InputLength + InputTake + crate::traits::ParseTo, + T: InputIter + InputLength + InputTake + crate::traits::ParseTo + Compare<&'static str>, ::Item: AsChar, ::IterElem: Clone, T: InputTakeAtPosition, @@ -1520,6 +1554,7 @@ where T: AsBytes, T: for<'a> Compare<&'a [u8]>, { + /* let (i, (sign, integer, fraction, exponent)) = recognize_float_parts(input)?; let mut float: f32 = minimal_lexical::parse_float( @@ -1532,6 +1567,15 @@ where } Ok((i, float)) + */ + let (i, s) = recognize_float_or_exceptions(input)?; + match s.parse_to() { + Some(f) => (Ok((i, f))), + None => Err(crate::Err::Error(E::from_error_kind( + i, + crate::error::ErrorKind::Float, + ))), + } } /// Recognizes floating point number in text format and returns a f64. @@ -1556,7 +1600,7 @@ pub fn double>(input: T) -> IResult where T: Slice> + Slice>, T: Clone + Offset, - T: InputIter + InputLength + InputTake + crate::traits::ParseTo, + T: InputIter + InputLength + InputTake + crate::traits::ParseTo + Compare<&'static str>, ::Item: AsChar, ::IterElem: Clone, T: InputTakeAtPosition, @@ -1564,6 +1608,7 @@ where T: AsBytes, T: for<'a> Compare<&'a [u8]>, { + /* let (i, (sign, integer, fraction, exponent)) = recognize_float_parts(input)?; let mut float: f64 = minimal_lexical::parse_float( @@ -1576,6 +1621,15 @@ where } Ok((i, float)) + */ + let (i, s) = recognize_float_or_exceptions(input)?; + match s.parse_to() { + Some(f) => (Ok((i, f))), + None => Err(crate::Err::Error(E::from_error_kind( + i, + crate::error::ErrorKind::Float, + ))), + } } #[cfg(test)] @@ -2022,6 +2076,7 @@ mod tests { "12.34", "-1.234E-12", "-1.234e-12", + "0.00000000000000000087", ]; for test in test_cases.drain(..) { @@ -2045,6 +2100,14 @@ mod tests { recognize_float(remaining_exponent), Err(Err::Incomplete(Needed::new(1))) ); + + let (_i, nan) = float::<_, ()>("NaN").unwrap(); + assert!(nan.is_nan()); + + let (_i, inf) = float::<_, ()>("inf").unwrap(); + assert!(inf.is_infinite()); + let (_i, inf) = float::<_, ()>("infinite").unwrap(); + assert!(inf.is_infinite()); } #[test]