about summary refs log tree commit diff
path: root/src/libcore
diff options
context:
space:
mode:
authorMarcel Hellwig <git@cookiesoft.de>2019-02-25 07:09:16 +0100
committerMarcel Hellwig <git@cookiesoft.de>2019-02-25 07:09:16 +0100
commit36bcbc352d4b48f0f3aea35fd9ca74e856f797c9 (patch)
treebfd1a10e6d28281158933d51f8c7cb2d1b48b504 /src/libcore
parent082c86175fcf72c355e6a889956fbea59e65bcdb (diff)
downloadrust-36bcbc352d4b48f0f3aea35fd9ca74e856f797c9.tar.gz
rust-36bcbc352d4b48f0f3aea35fd9ca74e856f797c9.zip
Add FromStr impl for NonZero types
Diffstat (limited to 'src/libcore')
-rw-r--r--src/libcore/num/mod.rs106
-rw-r--r--src/libcore/tests/nonzero.rs17
2 files changed, 123 insertions, 0 deletions
diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs
index 5b7d5f45d92..1479b891fa2 100644
--- a/src/libcore/num/mod.rs
+++ b/src/libcore/num/mod.rs
@@ -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,
diff --git a/src/libcore/tests/nonzero.rs b/src/libcore/tests/nonzero.rs
index 4532568ee0c..6e2d4588edc 100644
--- a/src/libcore/tests/nonzero.rs
+++ b/src/libcore/tests/nonzero.rs
@@ -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
+        })
+    );
+}