1use super::*;
3use num;
4
5fn parse_uint_internal<T: num::Integer + num::CheckedAdd + num::CheckedMul + num::FromPrimitive>(
7 chars: &mut dyn PeekableIterator<Item = char>,
8 mut radix: Option<u32>,
9) -> Option<T> {
10 let mut ret = T::zero();
11 let mut any = false;
12
13 if radix.is_none() {
14 if let Some('0') = chars.peek() {
15 chars.next();
16 any = true;
17
18 match chars.peek() {
19 Some('x') | Some('X') => {
20 radix = Some(16);
21 chars.next();
22 any = false; }
24 _ => {}
25 }
26 }
27 }
28
29 let radix = radix.unwrap_or(10);
30
31 while let Some(dig) = chars.peek() {
32 match dig.to_digit(radix) {
33 Some(digit) => {
34 ret = ret.checked_mul(&T::from_u32(radix).unwrap()).unwrap();
35 ret = ret.checked_add(&T::from_u32(digit).unwrap()).unwrap();
36
37 chars.next();
38 any = true;
39 }
40 None => break,
41 }
42 }
43
44 if any {
45 Some(ret)
46 } else {
47 None
48 }
49}
50
51pub fn parse_uint_from_iter_with_radix<
53 T: num::Integer + num::CheckedAdd + num::CheckedMul + num::FromPrimitive,
54>(
55 chars: &mut dyn PeekableIterator<Item = char>,
56 radix: Option<u32>,
57 whitespace: bool,
58) -> Option<T> {
59 while let Some(ch) = chars.peek() {
60 if whitespace && ch.is_whitespace() {
61 chars.next();
62 continue;
63 } else if *ch == '+' {
64 chars.next();
65 }
66
67 break;
68 }
69
70 parse_uint_internal::<T>(chars, radix)
71}
72
73pub fn parse_uint_from_iter<
75 T: num::Integer + num::CheckedAdd + num::CheckedMul + num::FromPrimitive,
76>(
77 chars: &mut dyn PeekableIterator<Item = char>,
78 whitespace: bool,
79) -> Option<T> {
80 parse_uint_from_iter_with_radix(chars, None, whitespace)
81}
82
83pub fn parse_int_from_iter_with_radix<
85 T: num::Integer + num::CheckedAdd + num::CheckedMul + num::FromPrimitive + num::Signed,
86>(
87 chars: &mut dyn PeekableIterator<Item = char>,
88 radix: Option<u32>,
89 whitespace: bool,
90) -> Option<T> {
91 let mut neg = false;
92
93 while let Some(ch) = chars.peek() {
94 if whitespace && ch.is_whitespace() {
95 chars.next();
96 continue;
97 }
98
99 if *ch == '+' || *ch == '-' {
100 neg = *ch == '-';
101 chars.next();
102 }
103
104 break;
105 }
106
107 if let Some(ret) = parse_uint_internal::<T>(chars, radix) {
108 if neg {
109 Some(-ret)
110 } else {
111 Some(ret)
112 }
113 } else {
114 None
115 }
116}
117
118pub fn parse_int_from_iter<
120 T: num::Integer + num::CheckedAdd + num::CheckedMul + num::FromPrimitive + num::Signed,
121>(
122 chars: &mut dyn PeekableIterator<Item = char>,
123 whitespace: bool,
124) -> Option<T> {
125 parse_int_from_iter_with_radix::<T>(chars, None, whitespace)
126}
127
128pub fn parse_uint_with_radix<
130 T: num::Integer + num::CheckedAdd + num::CheckedMul + num::FromPrimitive,
131>(
132 s: &str,
133 radix: u32,
134) -> Option<T> {
135 parse_uint_from_iter_with_radix::<T>(&mut s.chars().peekable(), Some(radix), true)
136}
137
138pub fn parse_uint<T: num::Integer + num::CheckedAdd + num::CheckedMul + num::FromPrimitive>(
140 s: &str,
141) -> Option<T> {
142 parse_uint_from_iter_with_radix::<T>(&mut s.chars().peekable(), None, true)
143}
144
145pub fn parse_int_with_radix<
147 T: num::Integer + num::CheckedAdd + num::CheckedMul + num::FromPrimitive + num::Signed,
148>(
149 s: &str,
150 radix: u32,
151) -> Option<T> {
152 parse_int_from_iter_with_radix::<T>(&mut s.chars().peekable(), Some(radix), true)
153}
154
155pub fn parse_int<
157 T: num::Integer + num::CheckedAdd + num::CheckedMul + num::FromPrimitive + num::Signed,
158>(
159 s: &str,
160) -> Option<T> {
161 parse_int_from_iter_with_radix::<T>(&mut s.chars().peekable(), None, true)
162}
163
164#[test]
165fn test_parse_uint_i64() {
166 assert_eq!(parse_uint::<i64>(" 123hello "), Some(123i64));
167 assert_eq!(parse_uint::<i64>(" 0xcafebabe "), Some(3405691582i64));
168 assert_eq!(parse_uint::<i64>(" 0 "), Some(0));
169 assert_eq!(parse_uint::<i64>(" 0x "), None);
170 assert_eq!(parse_uint::<i64>(" 0x1 "), Some(1));
171 assert_eq!(parse_uint::<i64>(" 456hello "), Some(456i64));
172 assert_eq!(parse_uint::<i64>(" -789hello "), None);
173}
174
175#[test]
176fn test_parse_uint_base16_i64() {
177 assert_eq!(
178 parse_uint_with_radix::<i64>("CAFEBABE", 16),
179 Some(3405691582i64)
180 );
181 assert_eq!(
182 parse_uint_with_radix::<i64>(" cafebabeyeah", 16),
183 Some(3405691582i64)
184 );
185 assert_eq!(parse_int_with_radix::<i64>(" 0xcafebabeyeah", 16), Some(0));
186}
187
188#[test]
189fn test_parse_int_i64() {
190 assert_eq!(parse_int::<i64>("123hello"), Some(123i64));
191 assert_eq!(parse_int::<i64>(" 456hello"), Some(456i64));
192 assert_eq!(parse_int::<i64>(" -789hello"), Some(-789i64));
193}
194
195#[test]
196fn test_parse_int_base16_i64() {
197 assert_eq!(
198 parse_int_with_radix::<i64>(" -CAFEBABE", 16),
199 Some(-3405691582i64)
200 );
201 assert_eq!(
202 parse_int_with_radix::<i64>(" -cafebabeyeah", 16),
203 Some(-3405691582i64)
204 );
205 assert_eq!(
206 parse_int_with_radix::<i64>(" -0xcafebabeyeah", 16),
207 Some(0)
208 );
209}
210
211#[test]
212fn test_readme() {
213 assert_eq!(parse_uint::<i32>("+123 as i32 "), Some(123i32));
214 assert_eq!(parse_int::<i32>(" -123 as i32 "), Some(-123i32));
215 assert_eq!(parse_uint::<i64>("+123 as i64 "), Some(123i64));
216 assert_eq!(parse_int::<i64>(" -123 as i64 "), Some(-123i64));
217
218 assert_eq!(parse_int::<i64>(" - 1 is invalid "), None);
219 assert_eq!(
220 parse_uint::<u64>(" -123 as u64, parse_int() not available for this type "),
221 None
222 );
223 assert_eq!(
224 parse_uint::<usize>(" 0xcafebabe triggers hex-mode parsing "),
225 Some(3405691582usize)
226 );
227}