use std::any::type_name;
use itertools::Itertools;
use lexical_core::FromLexical;
pub trait ParseNumber {
fn parse_number<N: FromLexical>(&self) -> N;
fn parse_numbers<N: FromLexical>(&self) -> impl Iterator<Item = N>;
fn parse_numbers_array<N: FromLexical, const COUNT: usize>(&self) -> [N; COUNT];
}
impl ParseNumber for [u8] {
#[inline]
fn parse_number<N: FromLexical>(&self) -> N {
lexical_core::parse(self)
.unwrap_or_else(|_| panic!("Expected {}, got {self:?}", type_name::<N>()))
}
#[inline]
fn parse_numbers<N: FromLexical>(&self) -> impl Iterator<Item = N> {
self.split(|&b| !(b.is_ascii_digit() || b == b'-'))
.filter(|s| !s.is_empty())
.map(ParseNumber::parse_number)
}
#[inline]
fn parse_numbers_array<N: FromLexical, const COUNT: usize>(&self) -> [N; COUNT] {
self.parse_numbers()
.collect_array()
.unwrap_or_else(|| panic!("Expected exactly {COUNT} {}", type_name::<N>()))
}
}
impl ParseNumber for str {
#[inline]
fn parse_number<N: FromLexical>(&self) -> N {
self.as_bytes().parse_number()
}
#[inline]
fn parse_numbers<N: FromLexical>(&self) -> impl Iterator<Item = N> {
self.as_bytes().parse_numbers()
}
#[inline]
fn parse_numbers_array<N: FromLexical, const COUNT: usize>(&self) -> [N; COUNT] {
self.as_bytes().parse_numbers_array()
}
}
#[inline]
pub fn parse_numbers_whitespace<N>(input: &str) -> impl Iterator<Item = N>
where
N: FromLexical,
{
input.split_ascii_whitespace().map(str::parse_number)
}
#[cfg(test)]
mod tests {
use super::{ParseNumber, parse_numbers_whitespace};
#[test]
fn u8_array_parse_number() {
let input = b"-8";
let expected = -8;
let output: i8 = input.parse_number();
assert_eq!(expected, output, "\n input: {input:?}");
}
#[test]
#[should_panic = "Expected"]
fn u8_array_parse_number_panic() {
let _: i8 = b"u8".parse_number();
}
#[test]
fn u8_array_parse_numbers() {
let input = b"-8,7 4!!!-1hello0";
let expected = vec![-8, 7, 4, -1, 0];
let output: Vec<i8> = input.parse_numbers().collect();
assert_eq!(expected, output, "\n input: {input:?}");
}
#[test]
fn u8_array_parse_numbers_array() {
let input = b"-8,7 4!!!-1hello0";
let expected = [-8, 7, 4, -1, 0];
let output: [i8; 5] = input.parse_numbers_array();
assert_eq!(expected, output, "\n input: {input:?}");
}
#[test]
#[should_panic = "Expected exactly"]
fn u8_array_parse_numbers_array_panic() {
let _: [i8; 5] = b"-8,7 4!!!-1hello0and13".parse_numbers_array();
}
#[test]
fn str_parse_number() {
let input = "-8";
let expected = -8;
let output: i8 = input.parse_number();
assert_eq!(expected, output, "\n input: {input:?}");
}
#[test]
#[should_panic = "Expected"]
fn str_parse_number_panic() {
let _: i8 = "u8".parse_number();
}
#[test]
fn str_parse_numbers() {
let input = "-8,7 4!!!-1hello0";
let expected = vec![-8, 7, 4, -1, 0];
let output: Vec<i8> = input.parse_numbers().collect();
assert_eq!(expected, output, "\n input: {input:?}");
}
#[test]
fn str_parse_numbers_array() {
let input = "-8,7 4!!!-1hello0";
let expected = [-8, 7, 4, -1, 0];
let output: [i8; 5] = input.parse_numbers_array();
assert_eq!(expected, output, "\n input: {input:?}");
}
#[test]
#[should_panic = "Expected exactly"]
fn str_array_parse_numbers_array_panic() {
let _: [i8; 5] = "-8,7 4!!!-1hello0and13".parse_numbers_array();
}
#[test]
fn str_parse_numbers_whitespace() {
let input = "-8 7 4 -1 0";
let expected = vec![-8, 7, 4, -1, 0];
let output: Vec<i8> = parse_numbers_whitespace(input).collect();
assert_eq!(expected, output, "\n input: {input:?}");
}
}