use nom::character::complete::{char, digit1};
use nom::{
branch::alt,
combinator::{map, opt, recognize},
error::{ErrorKind, ParseError},
sequence::pair,
AsBytes, AsChar, Compare, IResult, Input, Offset, ParseTo, Parser,
};
pub fn double_no_exponent<T, E: ParseError<T>>(input: T) -> IResult<T, f64, E>
where
T: AsBytes + Clone + Input + Offset + ParseTo<f64> + Compare<&'static str>,
<T as Input>::Item: AsChar,
<T as Input>::Iter: Clone,
T: for<'a> Compare<&'a [u8]>,
{
let (i, s) = recognize_float_or_exceptions(input)?;
match s.parse_to() {
Some(f) => Ok((i, f)),
None => Err(nom::Err::Error(E::from_error_kind(
i,
nom::error::ErrorKind::Float,
))),
}
}
#[doc(hidden)]
pub fn recognize_float_or_exceptions<T, E: ParseError<T>>(input: T) -> IResult<T, T, E>
where
T: Clone + Offset + Input + Compare<&'static str>,
<T as Input>::Item: AsChar,
{
alt((
|i: T| {
recognize_float::<_, E>(i.clone()).map_err(|e| match e {
nom::Err::Error(_) => nom::Err::Error(E::from_error_kind(i, ErrorKind::Float)),
nom::Err::Failure(_) => nom::Err::Failure(E::from_error_kind(i, ErrorKind::Float)),
nom::Err::Incomplete(needed) => nom::Err::Incomplete(needed),
})
},
|i: T| {
nom::bytes::complete::tag_no_case::<_, _, E>("nan")(i.clone())
.map_err(|_| nom::Err::Error(E::from_error_kind(i, ErrorKind::Float)))
},
|i: T| {
nom::bytes::complete::tag_no_case::<_, _, E>("infinity")(i.clone())
.map_err(|_| nom::Err::Error(E::from_error_kind(i, ErrorKind::Float)))
},
|i: T| {
nom::bytes::complete::tag_no_case::<_, _, E>("inf")(i.clone())
.map_err(|_| nom::Err::Error(E::from_error_kind(i, ErrorKind::Float)))
},
))
.parse(input)
}
#[rustfmt::skip]
pub fn recognize_float<T, E:ParseError<T>>(input: T) -> IResult<T, T, E>
where
T: Clone + Offset + Input,
<T as Input>::Item: AsChar,
{
recognize((
opt(alt((char('+'), char('-')))),
alt((
map((digit1, opt(pair(char('.'), opt(digit1)))), |_| ()),
map((char('.'), digit1), |_| ())
)),
)).parse(input)
}