Parse a 64-bit unsigned number.
(s: &str)
| 252 | |
| 253 | /// Parse a 64-bit unsigned number. |
| 254 | fn parse_u64(s: &str) -> Result<u64, &'static str> { |
| 255 | let mut value: u64 = 0; |
| 256 | let mut digits = 0; |
| 257 | |
| 258 | if s.starts_with("-0x") { |
| 259 | return Err("Invalid character in hexadecimal number"); |
| 260 | } else if let Some(num) = s.strip_prefix("0x") { |
| 261 | // Hexadecimal. |
| 262 | for ch in num.chars() { |
| 263 | match ch.to_digit(16) { |
| 264 | Some(digit) => { |
| 265 | digits += 1; |
| 266 | if digits > 16 { |
| 267 | return Err("Too many hexadecimal digits"); |
| 268 | } |
| 269 | // This can't overflow given the digit limit. |
| 270 | value = (value << 4) | u64::from(digit); |
| 271 | } |
| 272 | None => { |
| 273 | // Allow embedded underscores, but fail on anything else. |
| 274 | if ch != '_' { |
| 275 | return Err("Invalid character in hexadecimal number"); |
| 276 | } |
| 277 | } |
| 278 | } |
| 279 | } |
| 280 | } else { |
| 281 | // Decimal number, possibly negative. |
| 282 | for ch in s.chars() { |
| 283 | match ch.to_digit(10) { |
| 284 | Some(digit) => { |
| 285 | digits += 1; |
| 286 | match value.checked_mul(10) { |
| 287 | None => return Err("Too large decimal number"), |
| 288 | Some(v) => value = v, |
| 289 | } |
| 290 | match value.checked_add(u64::from(digit)) { |
| 291 | None => return Err("Too large decimal number"), |
| 292 | Some(v) => value = v, |
| 293 | } |
| 294 | } |
| 295 | None => { |
| 296 | // Allow embedded underscores, but fail on anything else. |
| 297 | if ch != '_' { |
| 298 | return Err("Invalid character in decimal number"); |
| 299 | } |
| 300 | } |
| 301 | } |
| 302 | } |
| 303 | } |
| 304 | |
| 305 | if digits == 0 { |
| 306 | return Err("No digits in number"); |
| 307 | } |
| 308 | |
| 309 | Ok(value) |
| 310 | } |
| 311 |
no test coverage detected