From 36bcbc352d4b48f0f3aea35fd9ca74e856f797c9 Mon Sep 17 00:00:00 2001 From: Marcel Hellwig Date: Mon, 25 Feb 2019 07:09:16 +0100 Subject: [PATCH 1/5] Add FromStr impl for NonZero types --- src/libcore/num/mod.rs | 106 +++++++++++++++++++++++++++++++++++ src/libcore/tests/nonzero.rs | 17 ++++++ 2 files changed, 123 insertions(+) diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 5b7d5f45d9246..1479b891fa2b6 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 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::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 4532568ee0c16..6e2d4588edc71 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 + }) + ); +} From ce30d4e1b947f8580636909c4c6f5aaeb254ea4c Mon Sep 17 00:00:00 2001 From: Marcel Hellwig Date: Wed, 27 Feb 2019 18:37:35 +0100 Subject: [PATCH 2/5] replaced nonzeroparseerror with regular interror --- src/libcore/num/mod.rs | 102 ++++------------------------------- src/libcore/tests/nonzero.rs | 20 ++++--- 2 files changed, 23 insertions(+), 99 deletions(-) diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 1479b891fa2b6..77b709a050d57 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -112,103 +112,15 @@ 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 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")] + #[stable(feature = "nonzero_parse", since = "1.35.0")] impl FromStr for $t { - type Err = ParseNonZeroIntError; + type Err = ParseIntError; fn from_str(src: &str) -> Result { Self::new(from_str_radix(src, 10)?) - .ok_or(ParseNonZeroIntError { - kind: NonZeroIntErrorKind::Zero + .ok_or(ParseIntError { + kind: IntErrorKind::Zero }) } } @@ -4968,6 +4880,11 @@ pub enum IntErrorKind { Overflow, /// Integer is too small to store in target integer type. Underflow, + /// Value was Zero + /// + /// This variant will be emitted when the parsing string has a value of zero, which + /// would be illegal for non-zero types. + Zero, } impl ParseIntError { @@ -4990,6 +4907,7 @@ impl ParseIntError { IntErrorKind::InvalidDigit => "invalid digit found in string", IntErrorKind::Overflow => "number too large to fit in target type", IntErrorKind::Underflow => "number too small to fit in target type", + IntErrorKind::Zero => "number would be zero for non-zero type", } } } diff --git a/src/libcore/tests/nonzero.rs b/src/libcore/tests/nonzero.rs index 6e2d4588edc71..764b0c249f9ca 100644 --- a/src/libcore/tests/nonzero.rs +++ b/src/libcore/tests/nonzero.rs @@ -129,17 +129,23 @@ fn test_from_signed_nonzero() { #[test] fn test_from_str() { - assert_eq!(FromStr::from_str("123"), Ok(NonZeroU8::new(123).unwrap())); + assert_eq!("123".parse::(), Ok(NonZeroU8::new(123).unwrap())); assert_eq!( - FromStr::from_str("0"), - Err(ParseNonZeroIntError { - kind: NonZeroIntErrorKind::Zero + "0".parse::(), + Err(ParseIntError { + kind: IntErrorKind::Zero }) ); assert_eq!( - FromStr::from_str("-1", - Err(ParseNonZeroIntError { - kind: NonZeroIntErrorKind::Underflow + "-1".parse::(), + Err(ParseIntError { + kind: IntErrorKind::Underflow + }) + ); + assert_eq!( + "129".parse::(), + Err(ParseIntError { + kind: IntErrorKind::Overflow }) ); } From 912ad6831ef0913afb7b0b5b6edc62bf002ebea8 Mon Sep 17 00:00:00 2001 From: Marcel Hellwig Date: Thu, 28 Feb 2019 07:45:33 +0100 Subject: [PATCH 3/5] fixed nonzero tests --- src/libcore/tests/nonzero.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/libcore/tests/nonzero.rs b/src/libcore/tests/nonzero.rs index 764b0c249f9ca..8e2d4177d08c7 100644 --- a/src/libcore/tests/nonzero.rs +++ b/src/libcore/tests/nonzero.rs @@ -1,6 +1,5 @@ -use core::num::{NonZeroU32, NonZeroI32}; -use core::option::Option; -use core::option::Option::{Some, None}; +use core::num::{IntErrorKind, NonZeroU8, NonZeroU32, NonZeroI32, ParseIntError}; +use core::option::Option::{self, Some, None}; use std::mem::size_of; #[test] @@ -143,7 +142,7 @@ fn test_from_str() { }) ); assert_eq!( - "129".parse::(), + "257".parse::(), Err(ParseIntError { kind: IntErrorKind::Overflow }) From ad240ea70c2ba4b4a03286320a7909e485507d75 Mon Sep 17 00:00:00 2001 From: Marcel Hellwig Date: Thu, 28 Feb 2019 14:47:32 +0100 Subject: [PATCH 4/5] add feature flag to test --- src/libcore/tests/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index 4cd734bad90a4..6db0d88e35554 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -34,6 +34,7 @@ #![feature(slice_internals)] #![feature(slice_partition_dedup)] #![feature(copy_within)] +#![feature(int_error_matching)] extern crate core; extern crate test; From 7330525e8fa8e873bc7feeb476fa161d20786a43 Mon Sep 17 00:00:00 2001 From: Marcel Hellwig Date: Thu, 28 Feb 2019 20:48:08 +0100 Subject: [PATCH 5/5] fixed tests again --- src/libcore/tests/nonzero.rs | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/src/libcore/tests/nonzero.rs b/src/libcore/tests/nonzero.rs index 8e2d4177d08c7..77e484601bc22 100644 --- a/src/libcore/tests/nonzero.rs +++ b/src/libcore/tests/nonzero.rs @@ -1,5 +1,5 @@ -use core::num::{IntErrorKind, NonZeroU8, NonZeroU32, NonZeroI32, ParseIntError}; -use core::option::Option::{self, Some, None}; +use core::num::{IntErrorKind, NonZeroI32, NonZeroI8, NonZeroU32, NonZeroU8}; +use core::option::Option::{self, None, Some}; use std::mem::size_of; #[test] @@ -130,21 +130,19 @@ fn test_from_signed_nonzero() { fn test_from_str() { assert_eq!("123".parse::(), Ok(NonZeroU8::new(123).unwrap())); assert_eq!( - "0".parse::(), - Err(ParseIntError { - kind: IntErrorKind::Zero - }) + "0".parse::().err().map(|e| e.kind().clone()), + Some(IntErrorKind::Zero) ); assert_eq!( - "-1".parse::(), - Err(ParseIntError { - kind: IntErrorKind::Underflow - }) + "-1".parse::().err().map(|e| e.kind().clone()), + Some(IntErrorKind::InvalidDigit) ); assert_eq!( - "257".parse::(), - Err(ParseIntError { - kind: IntErrorKind::Overflow - }) + "-129".parse::().err().map(|e| e.kind().clone()), + Some(IntErrorKind::Underflow) + ); + assert_eq!( + "257".parse::().err().map(|e| e.kind().clone()), + Some(IntErrorKind::Overflow) ); }