use crate::deserialize::Item;
use alloc::str::FromStr;
use alloc::string::ToString;
use core::cell::Cell;
use nom::character::streaming::{char, digit1};
use nom::error::{ErrorKind, ParseError};
use nom::sequence::preceded;
use nom::Parser;
use nom::{AsChar, IResult, Input};
pub fn int<'a, I: Input + ToString, E: ParseError<I>>(input: I) -> IResult<I, Item, E>
where <I as Input>::Item: AsChar {
let string_int = preceded(char('-'), digit1).parse(input)?;
Ok((string_int.0, Item::Int(0 - i64::from_str(string_int.1.to_string().as_str()).map_err(|_| {
nom::Err::Error(E::from_error_kind(string_int.1, ErrorKind::Digit))
})?)))
}
#[test]
pub fn test_int() {
use nom::Finish;
use crate::DeserializeError;
assert_eq!(int::<&str, DeserializeError<&str>>("-727nya").finish().unwrap(), ("nya", Item::Int(-727)))
}
pub fn uint<'a, I: Input + ToString, E: ParseError<I>>(input: I) -> IResult<I, Item, E>
where <I as Input>::Item: AsChar {
let string_int = digit1.parse(input)?;
Ok((string_int.0, Item::UInt(u64::from_str(string_int.1.to_string().as_str()).map_err(|_| {
nom::Err::Error(E::from_error_kind(string_int.1, ErrorKind::Digit))
})?)))
}
#[test]
pub fn test_uint() {
use nom::Finish;
use crate::DeserializeError;
assert_eq!(uint::<&str, DeserializeError<&str>>("727nya").finish().unwrap(), ("nya", Item::UInt(727)))
}
fn float_matcher<I: Input, E: ParseError<I>>(input: I) -> IResult<I, I, E>
where <I as Input>::Item: AsChar {
let float_found = Cell::new(false);
let dot_found = Cell::new(false);
let e_found = Cell::new(false);
let must_be_digit = Cell::new(false);
let result = input.split_at_position1(|c| {
let dot = c.as_char() == '.';
let e = c.as_char() == 'e';
let is_digit = matches!(c.as_char(), '0'..='9');
if dot | e {
if dot {
if dot_found.get() {
float_found.set(false);
return true;
} else {
dot_found.set(true);
}
}
if e {
if e_found.get() {
float_found.set(false);
return true;
} else {
e_found.set(true);
}
}
float_found.replace(true);
must_be_digit.replace(true);
} else {
if must_be_digit.get() {
if is_digit {
must_be_digit.set(false);
} else {
float_found.set(false);
return true;
}
}
}
!(dot | e | is_digit)
}, ErrorKind::Digit);
if !float_found.get() {
Err(nom::Err::Error(E::from_error_kind(input, ErrorKind::IsNot)))
} else {
result
}
}
pub fn float<I: Input + ToString, E: ParseError<I>>(input: I) -> IResult<I, Item, E>
where <I as Input>::Item: AsChar {
let string_float = float_matcher.parse(input)?;
Ok((string_float.0, Item::Float(f64::from_str(string_float.1.to_string().as_str()).map_err(|_| {
nom::Err::Error(E::from_error_kind(string_float.1, ErrorKind::Digit))
})?)))
}
#[test]
pub fn test_float() {
use nom::Finish;
use crate::DeserializeError;
assert_eq!(float::<&str, DeserializeError<&str>>("7.27nya").finish().unwrap(), ("nya", Item::Float(7.27)));
match float::<&str, DeserializeError<&str>>("727nya").finish().unwrap_err() {
DeserializeError::ParseError(_, kind) => {
assert_eq!(kind, ErrorKind::IsNot);
}
_ => assert!(false),
}
match float::<&str, DeserializeError<&str>>("727.nya").finish().unwrap_err() {
DeserializeError::ParseError(_, kind) => {
assert_eq!(kind, ErrorKind::IsNot);
}
_ => assert!(false),
}
match float::<&str, DeserializeError<&str>>("72..7nya").finish().unwrap_err(){
DeserializeError::ParseError(_, kind) => {
assert_eq!(kind, ErrorKind::IsNot);
}
_ => assert!(false),
}
assert_eq!(float::<&str, DeserializeError<&str>>("7e27nya").finish().unwrap(), ("nya", Item::Float(7e27)))
}