use num_traits::Num;
#[inline]
pub fn parse<T: Num>(input: &str) -> Result<T, T::FromStrRadixErr> {
let input = input.trim().chars().filter(|&c| c != '_').collect::<String>();
if input.starts_with("0x") {
return T::from_str_radix(input.trim_start_matches("0x"), 16)
}
if input.starts_with("0b") {
return T::from_str_radix(input.trim_start_matches("0b"), 2)
}
if input.starts_with("0o") {
return T::from_str_radix(input.trim_start_matches("0o"), 8)
}
#[cfg(feature = "implicit-octal")]
{
if input.starts_with("0") {
return T::from_str_radix(input.trim_start_matches("0"), 8)
}
}
T::from_str_radix(&input, 10)
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn turbofish_usize_dec() {
let s = "42";
let u = parse::<usize>(s).unwrap();
assert_eq!(42, u);
}
#[test]
fn deduct_usize_dec() {
let s = "42";
let u = parse(s).unwrap();
assert_eq!(42usize, u);
}
macro_rules! int_parse {
($type:ident, $s:literal, $e:literal) => {
#[test]
fn $type() {
let u: Result<$type, _> = parse($s);
assert_eq!(Ok($e), u);
}
}
}
mod decimal {
use super::*;
int_parse!(usize, "42", 42);
int_parse!(isize, "42", 42);
int_parse!( u8, "42", 42);
int_parse!( i8, "42", 42);
int_parse!( u16, "42", 42);
int_parse!( i16, "42", 42);
int_parse!( u32, "42", 42);
int_parse!( i32, "42", 42);
int_parse!( u64, "42", 42);
int_parse!( i64, "42", 42);
int_parse!( u128, "42", 42);
int_parse!( i128, "42", 42);
}
mod hexadecimal {
use super::*;
int_parse!(usize, "0x42", 66);
int_parse!(isize, "0x42", 66);
int_parse!( u8, "0x42", 66);
int_parse!( i8, "0x42", 66);
int_parse!( u16, "0x42", 66);
int_parse!( i16, "0x42", 66);
int_parse!( u32, "0x42", 66);
int_parse!( i32, "0x42", 66);
int_parse!( u64, "0x42", 66);
int_parse!( i64, "0x42", 66);
int_parse!( u128, "0x42", 66);
int_parse!( i128, "0x42", 66);
}
mod octal_explicit {
use super::*;
int_parse!(usize, "0o42", 34);
int_parse!(isize, "0o42", 34);
int_parse!( u8, "0o42", 34);
int_parse!( i8, "0o42", 34);
int_parse!( u16, "0o42", 34);
int_parse!( i16, "0o42", 34);
int_parse!( u32, "0o42", 34);
int_parse!( i32, "0o42", 34);
int_parse!( u64, "0o42", 34);
int_parse!( i64, "0o42", 34);
int_parse!( u128, "0o42", 34);
int_parse!( i128, "0o42", 34);
}
#[cfg(feature = "implicit-octal")]
mod octal_implicit {
use super::*;
int_parse!(usize, "042", 34);
int_parse!(isize, "042", 34);
int_parse!( u8, "042", 34);
int_parse!( i8, "042", 34);
int_parse!( u16, "042", 34);
int_parse!( i16, "042", 34);
int_parse!( u32, "042", 34);
int_parse!( i32, "042", 34);
int_parse!( u64, "042", 34);
int_parse!( i64, "042", 34);
int_parse!( u128, "042", 34);
int_parse!( i128, "042", 34);
}
#[cfg(not(feature = "implicit-octal"))]
mod octal_implicit_disabled {
use super::*;
#[test]
fn no_implicit_is_int() {
let s = "042";
let u = parse::<usize>(s);
assert_eq!(Ok(42), u, "{:?}", u);
}
}
mod binary {
use super::*;
int_parse!(usize, "0b0110", 6);
int_parse!(isize, "0b0110", 6);
int_parse!( u8, "0b0110", 6);
int_parse!( i8, "0b0110", 6);
int_parse!( u16, "0b0110", 6);
int_parse!( i16, "0b0110", 6);
int_parse!( u32, "0b0110", 6);
int_parse!( i32, "0b0110", 6);
int_parse!( u64, "0b0110", 6);
int_parse!( i64, "0b0110", 6);
int_parse!( u128, "0b0110", 6);
int_parse!( i128, "0b0110", 6);
}
mod underscore {
use super::*;
int_parse!(usize, "0b0110_0110", 102);
int_parse!(isize, "0x0110_0110", 17_826_064);
int_parse!(u64, "0o0110_0110", 294_984);
int_parse!(u128, "1_100_110", 1_100_110);
#[cfg(feature = "implicit-octal")]
mod implicit_octal {
use super::*;
int_parse!(i128, "0110_0110", 294_984);
}
#[cfg(not(feature = "implicit-octal"))]
mod implicit_octal {
use super::*;
int_parse!(i128, "0110_0110", 1_100_110);
}
}
}