#[derive(Clone, Copy, Debug)]
pub(crate) enum ParseIntError {
InvalidDigit,
}
const fn parse_byte(b: u8, pow10: usize) -> Result<usize, ParseIntError> {
let r = b.wrapping_sub(48);
if r > 9 {
Err(ParseIntError::InvalidDigit)
} else {
Ok((r as usize) * pow10)
}
}
const POW10: [usize; 20] = {
let mut array = [0; 20];
let mut pow10 = 1usize;
let mut index = 20;
loop {
index -= 1;
array[index] = pow10;
if index == 0 {
break;
}
let (new_power, overflow) = pow10.overflowing_mul(10);
pow10 = new_power;
if overflow {
break;
}
}
array
};
const fn try_parse_usize(b: &str) -> Result<usize, ParseIntError> {
let bytes = b.as_bytes();
let mut result: usize = 0;
let len = bytes.len();
let mut index_const_table = POW10.len().wrapping_sub(len);
let mut index = 0;
while index < b.len() {
let a = bytes[index];
let p = POW10[index_const_table];
let r = match parse_byte(a, p) {
Err(e) => return Err(e),
Ok(d) => d,
};
result = result.wrapping_add(r);
index += 1;
index_const_table += 1;
}
Ok(result)
}
pub(crate) const fn parse_usize(b: &str) -> usize {
match try_parse_usize(b) {
Ok(v) => v,
Err(_) => panic!("could not parse usize"),
}
}
#[test]
fn test_parse() {
use alloc::string::ToString;
for i in 0..500 {
assert_eq!(parse_usize(&i.to_string()), i);
}
for bits in 0usize..core::mem::size_of::<usize>() * 8 {
let i = (1 << bits) - 1;
assert_eq!(parse_usize(&i.to_string()), i);
}
}