Skip to content

Commit 36bcbc3

Browse files
committed
Add FromStr impl for NonZero types
1 parent 082c861 commit 36bcbc3

File tree

2 files changed

+123
-0
lines changed

2 files changed

+123
-0
lines changed

src/libcore/num/mod.rs

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,112 @@ nonzero_integers! {
112112
#[stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroIsize(isize);
113113
}
114114

115+
/// An error which can be returned when parsing a non-zero integer.
116+
///
117+
/// # Potential causes
118+
///
119+
/// Among other causes, `ParseNonZeroIntError` can be thrown because of leading or trailing
120+
/// whitespace in the string e.g., when it is obtained from the standard input.
121+
/// Using the [`str.trim()`] method ensures that no whitespace remains before parsing.
122+
///
123+
/// [`str.trim()`]: ../../std/primitive.str.html#method.trim
124+
#[unstable(feature = "nonzero_parse", issue = "0")]
125+
#[derive(Debug, Clone, PartialEq, Eq)]
126+
pub struct ParseNonZeroIntError {
127+
kind: NonZeroIntErrorKind,
128+
}
129+
130+
/// Enum to store the various types of errors that can cause parsing a non-zero integer to fail.
131+
#[unstable(feature = "nonzero_parse", issue = "0")]
132+
#[derive(Debug, Clone, PartialEq, Eq)]
133+
#[non_exhaustive]
134+
pub enum NonZeroIntErrorKind {
135+
/// Value being parsed is empty.
136+
///
137+
/// Among other causes, this variant will be constructed when parsing an empty string.
138+
Empty,
139+
/// Contains an invalid digit.
140+
///
141+
/// Among other causes, this variant will be constructed when parsing a string that
142+
/// contains a letter.
143+
InvalidDigit,
144+
/// Integer is too large to store in target integer type.
145+
Overflow,
146+
/// Integer is too small to store in target integer type.
147+
Underflow,
148+
/// Integer contains the value `0` which is forbidden for a non-zero integer
149+
Zero,
150+
}
151+
152+
#[unstable(feature = "nonzero_parse", issue = "0")]
153+
impl From<ParseIntError> for ParseNonZeroIntError {
154+
fn from(p: ParseIntError) -> Self {
155+
use self::IntErrorKind as IK;
156+
use self::NonZeroIntErrorKind as NK;
157+
ParseNonZeroIntError {
158+
kind: match p.kind {
159+
IK::Empty => NK::Empty,
160+
IK::InvalidDigit => NK::InvalidDigit,
161+
IK::Overflow => NK::Overflow,
162+
IK::Underflow => NK::Underflow,
163+
},
164+
}
165+
}
166+
}
167+
168+
impl ParseNonZeroIntError {
169+
/// Outputs the detailed cause of parsing an integer failing.
170+
#[unstable(feature = "int_error_matching",
171+
reason = "it can be useful to match errors when making error messages \
172+
for integer parsing",
173+
issue = "22639")]
174+
pub fn kind(&self) -> &NonZeroIntErrorKind {
175+
&self.kind
176+
}
177+
178+
#[unstable(feature = "int_error_internals",
179+
reason = "available through Error trait and this method should \
180+
not be exposed publicly",
181+
issue = "0")]
182+
#[doc(hidden)]
183+
pub fn __description(&self) -> &str {
184+
match self.kind {
185+
NonZeroIntErrorKind::Empty => "cannot parse integer from empty string",
186+
NonZeroIntErrorKind::InvalidDigit => "invalid digit found in string",
187+
NonZeroIntErrorKind::Overflow => "number too large to fit in target type",
188+
NonZeroIntErrorKind::Underflow => "number too small to fit in target type",
189+
NonZeroIntErrorKind::Zero => "number is 0",
190+
}
191+
}
192+
193+
}
194+
195+
#[unstable(feature = "nonzero_parse", issue = "0")]
196+
impl fmt::Display for ParseNonZeroIntError {
197+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
198+
self.__description().fmt(f)
199+
}
200+
}
201+
202+
203+
macro_rules! from_str_radix_nzint_impl {
204+
($($t:ty)*) => {$(
205+
#[unstable(feature = "nonzero_parse", issue = "0")]
206+
impl FromStr for $t {
207+
type Err = ParseNonZeroIntError;
208+
fn from_str(src: &str) -> Result<Self, Self::Err> {
209+
Self::new(from_str_radix(src, 10)?)
210+
.ok_or(ParseNonZeroIntError {
211+
kind: NonZeroIntErrorKind::Zero
212+
})
213+
}
214+
}
215+
)*}
216+
}
217+
218+
from_str_radix_nzint_impl! { NonZeroU8 NonZeroU16 NonZeroU32 NonZeroU64 NonZeroU128 NonZeroUsize
219+
NonZeroI8 NonZeroI16 NonZeroI32 NonZeroI64 NonZeroI128 NonZeroIsize }
220+
115221
/// Provides intentionally-wrapped arithmetic on `T`.
116222
///
117223
/// Operations like `+` on `u32` values is intended to never overflow,

src/libcore/tests/nonzero.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,3 +126,20 @@ fn test_from_signed_nonzero() {
126126
let num: i32 = nz.into();
127127
assert_eq!(num, 1i32);
128128
}
129+
130+
#[test]
131+
fn test_from_str() {
132+
assert_eq!(FromStr::from_str("123"), Ok(NonZeroU8::new(123).unwrap()));
133+
assert_eq!(
134+
FromStr::from_str("0"),
135+
Err(ParseNonZeroIntError {
136+
kind: NonZeroIntErrorKind::Zero
137+
})
138+
);
139+
assert_eq!(
140+
FromStr::from_str("-1",
141+
Err(ParseNonZeroIntError {
142+
kind: NonZeroIntErrorKind::Underflow
143+
})
144+
);
145+
}

0 commit comments

Comments
 (0)