1use std::num;
6use thiserror::Error;
7
8use crate::util::bigint;
9
10#[derive(Error, Debug, Clone, Eq, PartialEq)]
11pub enum ParseIntError {
12 #[error(transparent)]
13 ParseIntError(#[from] num::ParseIntError),
14 #[error(transparent)]
15 ParseByteArrayError(#[from] bigint::ParseBigIntError),
16}
17
18pub trait ParseInt: Sized {
25 type FromStrRadixErr: Into<ParseIntError>;
26
27 fn from_str_radix(src: &str, radix: u32) -> Result<Self, Self::FromStrRadixErr>;
28
29 fn from_str(src: &str) -> Result<Self, ParseIntError> {
30 let (val, negative) = if let Some(v) = src.strip_prefix('-') {
31 (v, true)
32 } else if let Some(v) = src.strip_prefix('+') {
33 (v, false)
34 } else {
35 (src, false)
36 };
37
38 let (radix, digits) = match val.get(0..2) {
39 Some("0x") | Some("0X") => (16, &val[2..]),
40 Some("0o") | Some("0O") => (8, &val[2..]),
41 Some("0b") | Some("0B") => (2, &val[2..]),
42 _ if val.starts_with('0') => (8, val),
43 _ => (10, val),
44 };
45
46 if negative {
47 let mut digits = digits.to_string();
48 digits.insert(0, '-');
49 Self::from_str_radix(&digits, radix).map_err(Self::FromStrRadixErr::into)
50 } else {
51 Self::from_str_radix(digits, radix).map_err(Self::FromStrRadixErr::into)
52 }
53 }
54}
55
56macro_rules! impl_parse_int {
57 ($ty:ident) => {
58 impl ParseInt for $ty {
59 type FromStrRadixErr = num::ParseIntError;
60
61 fn from_str_radix(src: &str, radix: u32) -> Result<Self, Self::FromStrRadixErr> {
62 $ty::from_str_radix(src, radix)
63 }
64 }
65 };
66}
67
68impl_parse_int!(i8);
69impl_parse_int!(u8);
70impl_parse_int!(i16);
71impl_parse_int!(u16);
72impl_parse_int!(i32);
73impl_parse_int!(u32);
74impl_parse_int!(i64);
75impl_parse_int!(u64);
76impl_parse_int!(i128);
77impl_parse_int!(u128);
78impl_parse_int!(isize);
79impl_parse_int!(usize);
80
81#[cfg(test)]
82mod tests {
83 use super::*;
84
85 #[test]
86 fn test_i8() {
87 assert_eq!(i8::from_str("0"), Ok(0));
88 assert_eq!(i8::from_str("-1"), Ok(-1));
89 assert_eq!(i8::from_str("+100"), Ok(100));
90 assert_eq!(i8::from_str("-128"), Ok(-128));
91 assert_eq!(i8::from_str("0x10"), Ok(16));
92 assert_eq!(i8::from_str("-0x10"), Ok(-16));
93 assert_eq!(i8::from_str("0o10"), Ok(8));
94 assert_eq!(i8::from_str("-0o10"), Ok(-8));
95 assert_eq!(i8::from_str("0b10"), Ok(2));
96 assert_eq!(i8::from_str("-0b10"), Ok(-2));
97 assert_eq!(i8::from_str("012"), Ok(10));
98 assert!(i8::from_str("128").is_err());
99 assert!(i8::from_str("-129").is_err());
100 }
101
102 #[test]
103 fn test_u8() {
104 assert_eq!(u8::from_str("0"), Ok(0));
105 assert_eq!(u8::from_str("+100"), Ok(100));
106 assert_eq!(u8::from_str("128"), Ok(128));
107 assert_eq!(u8::from_str("255"), Ok(255));
108 assert_eq!(u8::from_str("0x10"), Ok(16));
109 assert_eq!(u8::from_str("0xFF"), Ok(255));
110 assert_eq!(u8::from_str("0o10"), Ok(8));
111 assert_eq!(u8::from_str("0b10000000"), Ok(128));
112 assert_eq!(u8::from_str("012"), Ok(10));
113 assert!(u8::from_str("-1").is_err());
114 assert!(u8::from_str("256").is_err());
115 }
116
117 #[test]
118 fn test_i16() {
119 assert_eq!(i16::from_str("0"), Ok(0));
120 assert_eq!(i16::from_str("-1"), Ok(-1));
121 assert_eq!(i16::from_str("+32767"), Ok(32767));
122 assert_eq!(i16::from_str("-32768"), Ok(-32768));
123 assert_eq!(i16::from_str("0x3fff"), Ok(16383));
124 assert_eq!(i16::from_str("-0x10"), Ok(-16));
125 assert_eq!(i16::from_str("0o10"), Ok(8));
126 assert_eq!(i16::from_str("-0o10"), Ok(-8));
127 assert_eq!(i16::from_str("0b10"), Ok(2));
128 assert_eq!(i16::from_str("-0b10"), Ok(-2));
129 assert_eq!(i16::from_str("012"), Ok(10));
130 assert!(i16::from_str("32768").is_err());
131 assert!(i16::from_str("-32769").is_err());
132 }
133
134 #[test]
135 fn test_u16() {
136 assert_eq!(u16::from_str("0"), Ok(0));
137 assert_eq!(u16::from_str("+100"), Ok(100));
138 assert_eq!(u16::from_str("32768"), Ok(32768));
139 assert_eq!(u16::from_str("65535"), Ok(65535));
140 assert_eq!(u16::from_str("0x10"), Ok(16));
141 assert_eq!(u16::from_str("0xFF"), Ok(255));
142 assert_eq!(u16::from_str("0o10"), Ok(8));
143 assert_eq!(u16::from_str("0b1000000000000000"), Ok(32768));
144 assert_eq!(u16::from_str("012"), Ok(10));
145 assert!(u16::from_str("-1").is_err());
146 assert!(u16::from_str("65536").is_err());
147 }
148
149 #[test]
150 fn test_i32() {
151 assert_eq!(i32::from_str("0"), Ok(0));
152 assert_eq!(i32::from_str("-1"), Ok(-1));
153 assert_eq!(i32::from_str("+2147483647"), Ok(2147483647));
154 assert_eq!(i32::from_str("-2147483648"), Ok(-2147483648));
155 assert_eq!(i32::from_str("0x7fffffff"), Ok(2147483647));
156 assert_eq!(i32::from_str("-0x10"), Ok(-16));
157 assert_eq!(i32::from_str("0o10"), Ok(8));
158 assert_eq!(i32::from_str("-0o10"), Ok(-8));
159 assert_eq!(i32::from_str("0b10"), Ok(2));
160 assert_eq!(i32::from_str("-0b10"), Ok(-2));
161 assert_eq!(i32::from_str("012"), Ok(10));
162 assert!(i32::from_str("2147483648").is_err());
163 assert!(i32::from_str("-2147483649").is_err());
164 }
165
166 #[test]
167 fn test_u32() {
168 assert_eq!(u32::from_str("0"), Ok(0));
169 assert_eq!(u32::from_str("+100"), Ok(100));
170 assert_eq!(u32::from_str("2147483648"), Ok(2147483648));
171 assert_eq!(u32::from_str("4294967295"), Ok(4294967295));
172 assert_eq!(u32::from_str("0x10"), Ok(16));
173 assert_eq!(u32::from_str("0xFF"), Ok(255));
174 assert_eq!(u32::from_str("0o10"), Ok(8));
175 assert_eq!(u32::from_str("012"), Ok(10));
176 assert_eq!(
177 u32::from_str("0b10000000000000000000000000000000"),
178 Ok(2147483648)
179 );
180 assert!(u32::from_str("-1").is_err());
181 assert!(u32::from_str("4294967296").is_err());
182 }
183
184 #[test]
185 fn test_i64() {
186 assert_eq!(i64::from_str("0"), Ok(0));
187 assert_eq!(i64::from_str("-1"), Ok(-1));
188 assert_eq!(
189 i64::from_str("+9223372036854775807"),
190 Ok(9223372036854775807)
191 );
192 assert_eq!(
193 i64::from_str("-9223372036854775808"),
194 Ok(-9223372036854775808)
195 );
196 assert_eq!(i64::from_str("0x7fffffff"), Ok(2147483647));
197 assert_eq!(i64::from_str("-0x10"), Ok(-16));
198 assert_eq!(i64::from_str("0o10"), Ok(8));
199 assert_eq!(i64::from_str("-0o10"), Ok(-8));
200 assert_eq!(i64::from_str("0b10"), Ok(2));
201 assert_eq!(i64::from_str("-0b10"), Ok(-2));
202 assert_eq!(i64::from_str("012"), Ok(10));
203 assert!(i64::from_str("9223372036854775808").is_err());
204 assert!(i64::from_str("-9223372036854775809").is_err());
205 }
206
207 #[test]
208 fn test_u64() {
209 assert_eq!(u64::from_str("0"), Ok(0));
210 assert_eq!(u64::from_str("+100"), Ok(100));
211 assert_eq!(
212 u64::from_str("+9223372036854775808"),
213 Ok(9223372036854775808)
214 );
215 assert_eq!(
216 u64::from_str("18446744073709551615"),
217 Ok(18446744073709551615)
218 );
219 assert_eq!(u64::from_str("0x10"), Ok(16));
220 assert_eq!(u64::from_str("0xFF"), Ok(255));
221 assert_eq!(u64::from_str("0o10"), Ok(8));
222 assert_eq!(
223 u64::from_str("0b10000000000000000000000000000000"),
224 Ok(2147483648)
225 );
226 assert_eq!(u64::from_str("012"), Ok(10));
227 assert!(u64::from_str("-1").is_err());
228 assert!(u64::from_str("18446744073709551616").is_err());
229 }
230
231 #[test]
232 fn test_isize() {
233 assert_eq!(isize::from_str("0"), Ok(0));
237 assert_eq!(isize::from_str("-1"), Ok(-1));
238 assert_eq!(isize::from_str("0x7f"), Ok(127));
239 assert_eq!(isize::from_str("-0x10"), Ok(-16));
240 assert_eq!(isize::from_str("0o10"), Ok(8));
241 assert_eq!(isize::from_str("-0o10"), Ok(-8));
242 assert_eq!(isize::from_str("0b10"), Ok(2));
243 assert_eq!(isize::from_str("-0b10"), Ok(-2));
244 assert_eq!(isize::from_str("012"), Ok(10));
245 }
246
247 #[test]
248 fn test_usize() {
249 assert_eq!(usize::from_str("0"), Ok(0));
253 assert_eq!(usize::from_str("+100"), Ok(100));
254 assert_eq!(usize::from_str("0x10"), Ok(16));
255 assert_eq!(usize::from_str("0xFF"), Ok(255));
256 assert_eq!(usize::from_str("0o10"), Ok(8));
257 assert_eq!(usize::from_str("012"), Ok(10));
258 assert!(usize::from_str("-1").is_err());
259 }
260}