buni-rs 1.2.0

Reference Buni serializer / deserializer in Rust
Documentation
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)))
}