buni-rs 1.0.1

Reference Buni deserializer in Rust
Documentation
use crate::deserialize::Item;
use nom::character::streaming::{char, digit1};
use nom::error::{ErrorKind, ParseError};
use nom::sequence::preceded;
use nom::Parser;
use nom::{AsChar, IResult, Input};
use core::cell::Cell;
use alloc::str::FromStr;
use alloc::string::ToString;

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;
    match int::<&str, DeserializeError<&str>>("-727nya").finish() {
        Ok(item) => assert_eq!(item, ("nya", Item::Int(-727))),
        Err(err) => panic!("{}", err),
    }
}

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;
    match uint::<&str, DeserializeError<&str>>("727nya").finish() {
        Ok(item) => assert_eq!(item, ("nya", Item::UInt(727))),
        Err(err) => panic!("{}", err),
    }
}

fn digit_or_dot_1<I: Input, E: ParseError<I>>(input: I) -> IResult<I, I, E>
where <I as Input>::Item: AsChar {
    let dot_found = Cell::new(false);
    let result = input.split_at_position1(|c| {
        let dot = c.as_char() == '.';
        if dot {
            dot_found.replace(true);
        }
        !(dot | matches!(c.as_char(), '0'..='9'))
    }, ErrorKind::Digit);
    if !dot_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 = digit_or_dot_1.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;
    match float::<&str, DeserializeError<&str>>("7.27nya").finish() {
        Ok(item) =>     assert_eq!(item, ("nya", Item::Float(7.27))),
        Err(err) => panic!("{}", err),
    }
    match float::<&str, DeserializeError<&str>>("727nya").finish() {
        Err(err) => match err {
            DeserializeError::ParseError(_, kind) => {
            assert_eq ! (kind, ErrorKind::IsNot);
            }
            _ => assert!(false),
        },
        Ok(_) => assert!(false),
    }
}