1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
use core::fmt::{self, Display, Formatter};
#[cfg(feature = "std")]
use std::error::Error;
pub trait FromStrRadix: Sized {
fn from_str_radix(s: &str, radix: u32) -> Result<Self, ParseError>;
}
macro_rules! from_str_radix_impl {
($($ty:ident)*) => { $(
impl FromStrRadix for $ty {
fn from_str_radix(src: &str, radix: u32) -> Result<Self, ParseError> {
assert!(
(2..=36).contains(&radix),
"from_str_radix: radix must lie in the range `[2, 36]` - found {}",
radix,
);
let src = src.as_bytes();
let (positive, digits) = match *src {
[b'+', ref digits @ ..] => (true, digits),
[b'-', ref digits @ ..] => (false, digits),
ref digits => (true, digits),
};
if digits.is_empty() {
return Err(ParseError {
kind: ParseErrorKind::NoDigits,
});
}
let overflow_kind = if positive {
ParseErrorKind::AboveMax
} else {
ParseErrorKind::BelowMin
};
let mut result: Self = 0;
for &digit in digits {
let digit_value =
char::from(digit)
.to_digit(radix)
.ok_or_else(|| ParseError {
kind: ParseErrorKind::InvalidDigit,
})?;
result = result
.checked_mul(radix as Self)
.ok_or_else(|| ParseError {
kind: overflow_kind,
})?;
result = if positive {
result.checked_add(digit_value as Self)
} else {
result.checked_sub(digit_value as Self)
}
.ok_or_else(|| ParseError {
kind: overflow_kind,
})?;
}
Ok(result)
}
}
)* }
}
from_str_radix_impl! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize }
#[derive(Debug, Clone)]
pub struct ParseError {
kind: ParseErrorKind,
}
impl ParseError {
#[must_use]
pub fn kind(&self) -> ParseErrorKind {
self.kind
}
}
impl Display for ParseError {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self.kind() {
ParseErrorKind::NoDigits => f.write_str("no digits found"),
ParseErrorKind::InvalidDigit => f.write_str("invalid digit found in string"),
ParseErrorKind::AboveMax => f.write_str("number too high to fit in target range"),
ParseErrorKind::BelowMin => f.write_str("number too low to fit in target range"),
}
}
}
#[cfg(feature = "std")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "std")))]
impl Error for ParseError {}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
pub enum ParseErrorKind {
#[non_exhaustive]
NoDigits,
#[non_exhaustive]
InvalidDigit,
#[non_exhaustive]
AboveMax,
#[non_exhaustive]
BelowMin,
}
pub fn error_below_min() -> ParseError {
ParseError {
kind: ParseErrorKind::BelowMin,
}
}
pub fn error_above_max() -> ParseError {
ParseError {
kind: ParseErrorKind::AboveMax,
}
}