sj 0.17.0

Some JSON implementation
Documentation
// License: see LICENSE file at root directory of `master` branch

//! # Number parser

#[cfg(feature="std")]
use {
    alloc::string::String,
    core::str::FromStr,
    crate::{Error, Number, Result},
};

#[cfg(feature="std")]
const MAX_I8_LEN: usize = 4;

#[cfg(feature="std")]
const MAX_I16_LEN: usize = 6;

#[cfg(feature="std")]
const MAX_I32_LEN: usize = 11;

#[cfg(feature="std")]
const MAX_I64_LEN: usize = 21;

#[cfg(feature="std")]
const MAX_I128_LEN: usize = 40;

#[cfg(feature="std")]
const MAX_INTEGER_LEN: usize = MAX_I128_LEN;

#[cfg(feature="std")]
const MAX_FLOAT_LEN: usize = 100;

#[cfg(feature="std")]
#[test]
fn tests() {
    macro_rules! test { ($($constant: ident, $ty: ty,)+) => {
        $(
            assert_eq!($constant, (<$ty>::max_value() as f64).log10().ceil() as usize + 1);
        )+
    }}
    test!(
        MAX_I8_LEN, u8,
        MAX_I16_LEN, u16,
        MAX_I32_LEN, u32,
        MAX_I64_LEN, u64,
        MAX_I128_LEN, u128,
    );
}

/// # Number parser
#[cfg(feature="std")]
#[derive(Debug)]
pub struct NumberParser {
    s: String,
    is_integer: bool,
}

#[cfg(feature="std")]
impl NumberParser {

    /// # Makes new instance
    pub fn new() -> Self {
        Self {
            s: String::with_capacity(MAX_INTEGER_LEN.max(MAX_FLOAT_LEN)),
            is_integer: true,
        }
    }

    /// # Adds new byte
    pub fn add(&mut self, b: &u8) -> Result<()> {
        match self.is_integer {
            true => if self.s.len() >= MAX_INTEGER_LEN {
                return Err(Error::from(__!("Integer too large")));
            },
            false => if self.s.len() >= MAX_FLOAT_LEN {
                return Err(Error::from(__!("Float too long")));
            },
        };

        let c = char::from(*b);
        match c {
            '-' | '+' => match self.s.is_empty() || self.s.ends_with(|c| c == 'e' || c == 'E') {
                true => self.s.push(c),
                false => return Err(Error::from(__!("Invalid sign: {s}{c}", s=self.s, c=c))),
            },
            'e' | 'E' | '.' => {
                if self.is_integer {
                    self.is_integer = false;
                }
                self.s.push(c);
            },
            '0'..='9' => self.s.push(c),
            _ => return Err(Error::from(__!("Invalid number: {s}{c}", s=self.s, c=c))),
        };

        Ok(())
    }

    /// # Parses
    pub fn parse(&self) -> Result<Number> {
        if self.s.is_empty() {
            return Err(Error::from(__!("Number is empty")));
        }

        fn parse_int<T, U>(s: &str) -> Result<Number> where T: Into<Number> + FromStr, U: Into<Number> + FromStr {
            match T::from_str(s) {
                Ok(n) => Ok(n.into()),
                Err(_) => match U::from_str(s) {
                    Ok(n) => Ok(n.into()),
                    Err(_) => Err(Error::from(__!("Invalid integer: {:?}", s))),
                },
            }
        }

        match self.is_integer {
            true => {
                let is_negative = self.s.starts_with(|c| c == '-');
                return match self.s.len() {
                    0..=MAX_I8_LEN => match is_negative {
                        true => parse_int::<i8, i16>(&self.s),
                        false => parse_int::<u8, u16>(&self.s),
                    },
                    MAX_I8_LEN..=MAX_I16_LEN => match is_negative {
                        true => parse_int::<i16, i32>(&self.s),
                        false => parse_int::<u16, u32>(&self.s),
                    },
                    MAX_I16_LEN..=MAX_I32_LEN => match is_negative {
                        true => parse_int::<i32, i64>(&self.s),
                        false => parse_int::<u32, u64>(&self.s),
                    },
                    MAX_I32_LEN..=MAX_I64_LEN => match is_negative {
                        true => parse_int::<i64, i128>(&self.s),
                        false => parse_int::<u64, u128>(&self.s),
                    },
                    _ => match is_negative {
                        true => i128::from_str(&self.s).map(|i| Number::from(i)).map_err(|_| Error::from(__!("Invalid integer: {:?}", self.s))),
                        false => u128::from_str(&self.s).map(|u| Number::from(u)).map_err(|_| Error::from(__!("Invalid integer: {:?}", self.s))),
                    },
                };
            },
            false => f64::from_str(&self.s).map(|f| f.into()).map_err(|e| Error::from(__!("{}", e))),
        }
    }

    /// # Resets
    pub fn reset(&mut self) {
        self.s.clear();
        self.is_integer = true;
    }

}