1use std::any::type_name;
2
3use itertools::Itertools;
4use lexical_core::FromLexical;
5
6pub trait ParseNumber {
8 fn parse_number<N: FromLexical>(&self) -> N;
10
11 fn parse_numbers<N: FromLexical>(&self) -> impl Iterator<Item = N>;
13
14 fn parse_numbers_array<N: FromLexical, const COUNT: usize>(&self) -> [N; COUNT];
17}
18
19impl ParseNumber for [u8] {
20 #[inline]
21 fn parse_number<N: FromLexical>(&self) -> N {
22 lexical_core::parse(self)
23 .unwrap_or_else(|_| panic!("Expected {}, got {self:?}", type_name::<N>()))
24 }
25
26 #[inline]
27 fn parse_numbers<N: FromLexical>(&self) -> impl Iterator<Item = N> {
28 self.split(|&b| !(b.is_ascii_digit() || b == b'-'))
29 .filter(|s| !s.is_empty())
30 .map(ParseNumber::parse_number)
31 }
32
33 #[inline]
34 fn parse_numbers_array<N: FromLexical, const COUNT: usize>(&self) -> [N; COUNT] {
35 self.parse_numbers()
36 .collect_array()
37 .unwrap_or_else(|| panic!("Expected exactly {COUNT} {}", type_name::<N>()))
38 }
39}
40
41impl ParseNumber for str {
42 #[inline]
43 fn parse_number<N: FromLexical>(&self) -> N {
44 self.as_bytes().parse_number()
45 }
46
47 #[inline]
48 fn parse_numbers<N: FromLexical>(&self) -> impl Iterator<Item = N> {
49 self.as_bytes().parse_numbers()
50 }
51
52 #[inline]
53 fn parse_numbers_array<N: FromLexical, const COUNT: usize>(&self) -> [N; COUNT] {
54 self.as_bytes().parse_numbers_array()
55 }
56}
57
58#[inline]
61pub fn parse_numbers_whitespace<N>(input: &str) -> impl Iterator<Item = N>
62where
63 N: FromLexical,
64{
65 input.split_ascii_whitespace().map(str::parse_number)
66}
67
68#[cfg(test)]
69mod tests {
70 use super::{ParseNumber, parse_numbers_whitespace};
71
72 #[test]
76 fn u8_array_parse_number() {
77 let input = b"-8";
78 let expected = -8;
79 let output: i8 = input.parse_number();
80 assert_eq!(expected, output, "\n input: {input:?}");
81 }
82
83 #[test]
84 #[should_panic = "Expected"]
85 fn u8_array_parse_number_panic() {
86 let _: i8 = b"u8".parse_number();
87 }
88
89 #[test]
90 fn u8_array_parse_numbers() {
91 let input = b"-8,7 4!!!-1hello0";
92 let expected = vec![-8, 7, 4, -1, 0];
93 let output: Vec<i8> = input.parse_numbers().collect();
94 assert_eq!(expected, output, "\n input: {input:?}");
95 }
96
97 #[test]
98 fn u8_array_parse_numbers_array() {
99 let input = b"-8,7 4!!!-1hello0";
100 let expected = [-8, 7, 4, -1, 0];
101 let output: [i8; 5] = input.parse_numbers_array();
102 assert_eq!(expected, output, "\n input: {input:?}");
103 }
104
105 #[test]
106 #[should_panic = "Expected exactly"]
107 fn u8_array_parse_numbers_array_panic() {
108 let _: [i8; 5] = b"-8,7 4!!!-1hello0and13".parse_numbers_array();
109 }
110
111 #[test]
115 fn str_parse_number() {
116 let input = "-8";
117 let expected = -8;
118 let output: i8 = input.parse_number();
119 assert_eq!(expected, output, "\n input: {input:?}");
120 }
121
122 #[test]
123 #[should_panic = "Expected"]
124 fn str_parse_number_panic() {
125 let _: i8 = "u8".parse_number();
126 }
127
128 #[test]
129 fn str_parse_numbers() {
130 let input = "-8,7 4!!!-1hello0";
131 let expected = vec![-8, 7, 4, -1, 0];
132 let output: Vec<i8> = input.parse_numbers().collect();
133 assert_eq!(expected, output, "\n input: {input:?}");
134 }
135
136 #[test]
137 fn str_parse_numbers_array() {
138 let input = "-8,7 4!!!-1hello0";
139 let expected = [-8, 7, 4, -1, 0];
140 let output: [i8; 5] = input.parse_numbers_array();
141 assert_eq!(expected, output, "\n input: {input:?}");
142 }
143
144 #[test]
145 #[should_panic = "Expected exactly"]
146 fn str_array_parse_numbers_array_panic() {
147 let _: [i8; 5] = "-8,7 4!!!-1hello0and13".parse_numbers_array();
148 }
149
150 #[test]
154 fn str_parse_numbers_whitespace() {
155 let input = "-8 7 4 -1 0";
156 let expected = vec![-8, 7, 4, -1, 0];
157 let output: Vec<i8> = parse_numbers_whitespace(input).collect();
158 assert_eq!(expected, output, "\n input: {input:?}");
159 }
160}