Skip to content

Add FromStr impl for NonZero types #58717

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Mar 29, 2019
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
106 changes: 106 additions & 0 deletions src/libcore/num/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,112 @@ nonzero_integers! {
#[stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroIsize(isize);
}

/// An error which can be returned when parsing a non-zero integer.
///
/// # Potential causes
///
/// Among other causes, `ParseNonZeroIntError` can be thrown because of leading or trailing
/// whitespace in the string e.g., when it is obtained from the standard input.
/// Using the [`str.trim()`] method ensures that no whitespace remains before parsing.
///
/// [`str.trim()`]: ../../std/primitive.str.html#method.trim
#[unstable(feature = "nonzero_parse", issue = "0")]
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ParseNonZeroIntError {
kind: NonZeroIntErrorKind,
}

/// Enum to store the various types of errors that can cause parsing a non-zero integer to fail.
#[unstable(feature = "nonzero_parse", issue = "0")]
#[derive(Debug, Clone, PartialEq, Eq)]
#[non_exhaustive]
pub enum NonZeroIntErrorKind {
/// Value being parsed is empty.
///
/// Among other causes, this variant will be constructed when parsing an empty string.
Empty,
/// Contains an invalid digit.
///
/// Among other causes, this variant will be constructed when parsing a string that
/// contains a letter.
InvalidDigit,
/// Integer is too large to store in target integer type.
Overflow,
/// Integer is too small to store in target integer type.
Underflow,
/// Integer contains the value `0` which is forbidden for a non-zero integer
Zero,
}

#[unstable(feature = "nonzero_parse", issue = "0")]
impl From<ParseIntError> for ParseNonZeroIntError {
fn from(p: ParseIntError) -> Self {
use self::IntErrorKind as IK;
use self::NonZeroIntErrorKind as NK;
ParseNonZeroIntError {
kind: match p.kind {
IK::Empty => NK::Empty,
IK::InvalidDigit => NK::InvalidDigit,
IK::Overflow => NK::Overflow,
IK::Underflow => NK::Underflow,
},
}
}
}

impl ParseNonZeroIntError {
/// Outputs the detailed cause of parsing an integer failing.
#[unstable(feature = "int_error_matching",
reason = "it can be useful to match errors when making error messages \
for integer parsing",
issue = "22639")]
pub fn kind(&self) -> &NonZeroIntErrorKind {
&self.kind
}

#[unstable(feature = "int_error_internals",
reason = "available through Error trait and this method should \
not be exposed publicly",
issue = "0")]
#[doc(hidden)]
pub fn __description(&self) -> &str {
match self.kind {
NonZeroIntErrorKind::Empty => "cannot parse integer from empty string",
NonZeroIntErrorKind::InvalidDigit => "invalid digit found in string",
NonZeroIntErrorKind::Overflow => "number too large to fit in target type",
NonZeroIntErrorKind::Underflow => "number too small to fit in target type",
NonZeroIntErrorKind::Zero => "number is 0",
}
}

}

#[unstable(feature = "nonzero_parse", issue = "0")]
impl fmt::Display for ParseNonZeroIntError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.__description().fmt(f)
}
}


macro_rules! from_str_radix_nzint_impl {
($($t:ty)*) => {$(
#[unstable(feature = "nonzero_parse", issue = "0")]
impl FromStr for $t {
type Err = ParseNonZeroIntError;
fn from_str(src: &str) -> Result<Self, Self::Err> {
Self::new(from_str_radix(src, 10)?)
.ok_or(ParseNonZeroIntError {
kind: NonZeroIntErrorKind::Zero
})
}
}
)*}
}

from_str_radix_nzint_impl! { NonZeroU8 NonZeroU16 NonZeroU32 NonZeroU64 NonZeroU128 NonZeroUsize
NonZeroI8 NonZeroI16 NonZeroI32 NonZeroI64 NonZeroI128 NonZeroIsize }

/// Provides intentionally-wrapped arithmetic on `T`.
///
/// Operations like `+` on `u32` values is intended to never overflow,
Expand Down
17 changes: 17 additions & 0 deletions src/libcore/tests/nonzero.rs
Original file line number Diff line number Diff line change
Expand Up @@ -126,3 +126,20 @@ fn test_from_signed_nonzero() {
let num: i32 = nz.into();
assert_eq!(num, 1i32);
}

#[test]
fn test_from_str() {
assert_eq!(FromStr::from_str("123"), Ok(NonZeroU8::new(123).unwrap()));
assert_eq!(
FromStr::from_str("0"),
Err(ParseNonZeroIntError {
kind: NonZeroIntErrorKind::Zero
})
);
assert_eq!(
FromStr::from_str("-1",
Err(ParseNonZeroIntError {
kind: NonZeroIntErrorKind::Underflow
})
);
}