diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs index e1ab7ac5ff045..5443baa3b664f 100644 --- a/library/core/src/num/int_macros.rs +++ b/library/core/src/num/int_macros.rs @@ -62,8 +62,37 @@ macro_rules! int_impl { #[doc = concat!("assert_eq!(", stringify!($SelfT), "::from_str_radix(\"A\", 16), Ok(10));")] /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[track_caller] pub fn from_str_radix(src: &str, radix: u32) -> Result { - from_str_radix(src, radix) + from_ascii_radix(src.as_bytes(), radix) + } + + /// Parses an integer in a given base from a slice of bytes. + /// + /// The bytes are interpreted as ASCII characters. Accepts an optional + /// `+` or `-` sign followed by digits. Leading and trailing whitespace + /// are rejected. + /// Digits are a subset of these characters, depending on `radix`: + /// + /// * `0-9` + /// * `a-z` + /// * `A-Z` + /// + /// # Panics + /// + /// This function panics if `radix` is not in the range from 2 to 36. + /// + /// # Examples + /// + /// ``` + /// #![feature(int_from_ascii_radix)] + /// + #[doc = concat!("assert_eq!(", stringify!($SelfT), "::from_ascii_radix(b\"+100\", 2), Ok(4));")] + /// ``` + #[unstable(feature = "int_from_ascii_radix", issue = "none")] + #[track_caller] + pub fn from_ascii_radix(src: &[u8], radix: u32) -> Result { + from_ascii_radix(src, radix) } /// Returns the number of ones in the binary representation of `self`. diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs index b2328b001de90..c1eaa2e3f1ddb 100644 --- a/library/core/src/num/mod.rs +++ b/library/core/src/num/mod.rs @@ -1055,7 +1055,7 @@ pub enum FpCategory { } #[doc(hidden)] -trait FromStrRadixHelper: +trait FromAsciiRadixHelper: PartialOrd + Copy + Add + Sub + Mul { const MIN: Self; @@ -1071,7 +1071,7 @@ macro_rules! from_str_radix_int_impl { impl FromStr for $t { type Err = ParseIntError; fn from_str(src: &str) -> Result { - from_str_radix(src, 10) + from_ascii_radix(src.as_bytes(), 10) } } )*} @@ -1079,7 +1079,7 @@ macro_rules! from_str_radix_int_impl { from_str_radix_int_impl! { isize i8 i16 i32 i64 i128 usize u8 u16 u32 u64 u128 } macro_rules! impl_helper_for { - ($($t:ty)*) => ($(impl FromStrRadixHelper for $t { + ($($t:ty)*) => ($(impl FromAsciiRadixHelper for $t { const MIN: Self = Self::MIN; #[inline] fn from_u32(u: u32) -> Self { u as Self } @@ -1110,15 +1110,11 @@ pub fn can_not_overflow(radix: u32, is_signed_ty: bool, digits: &[u8]) -> boo radix <= 16 && digits.len() <= mem::size_of::() * 2 - is_signed_ty as usize } -fn from_str_radix(src: &str, radix: u32) -> Result { +fn from_ascii_radix(src: &[u8], radix: u32) -> Result { use self::IntErrorKind::*; use self::ParseIntError as PIE; - assert!( - (2..=36).contains(&radix), - "from_str_radix_int: must lie in the range `[2, 36]` - found {}", - radix - ); + assert!((2..=36).contains(&radix), "radix must lie in the range `[2, 36]` - found {}", radix); if src.is_empty() { return Err(PIE { kind: Empty }); @@ -1126,12 +1122,6 @@ fn from_str_radix(src: &str, radix: u32) -> Result T::MIN; - // all valid digits are ascii, so we will just iterate over the utf8 bytes - // and cast them to chars. .to_digit() will safely return None for anything - // other than a valid ascii digit for the given radix, including the first-byte - // of multi-byte sequences - let src = src.as_bytes(); - let (is_positive, digits) = match src[0] { b'+' | b'-' if src[1..].is_empty() => { return Err(PIE { kind: InvalidDigit }); diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index 141cbc7669b0b..35de3bfba9672 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -4,7 +4,7 @@ use crate::fmt; use crate::ops::{BitOr, BitOrAssign, Div, Rem}; use crate::str::FromStr; -use super::from_str_radix; +use super::from_ascii_radix; use super::{IntErrorKind, ParseIntError}; use crate::intrinsics; @@ -182,7 +182,7 @@ macro_rules! from_str_radix_nzint_impl { impl FromStr for $t { type Err = ParseIntError; fn from_str(src: &str) -> Result { - Self::new(from_str_radix(src, 10)?) + Self::new(from_ascii_radix(src.as_bytes(), 10)?) .ok_or(ParseIntError { kind: IntErrorKind::Zero }) diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index af74faa90b110..0e48b86057d47 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -63,8 +63,37 @@ macro_rules! uint_impl { #[doc = concat!("assert_eq!(", stringify!($SelfT), "::from_str_radix(\"A\", 16), Ok(10));")] /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[track_caller] pub fn from_str_radix(src: &str, radix: u32) -> Result { - from_str_radix(src, radix) + from_ascii_radix(src.as_bytes(), radix) + } + + /// Parses an integer in a given base from a slice of bytes. + /// + /// The bytes are interpreted as ASCII characters. Accepts an + /// optional `+` sign followed by digits. Leading and trailing + /// whitespace are rejected. + /// Digits are a subset of these characters, depending on `radix`: + /// + /// * `0-9` + /// * `a-z` + /// * `A-Z` + /// + /// # Panics + /// + /// This function panics if `radix` is not in the range from 2 to 36. + /// + /// # Examples + /// + /// ``` + /// #![feature(int_from_ascii_radix)] + /// + #[doc = concat!("assert_eq!(", stringify!($SelfT), "::from_ascii_radix(b\"+100\", 2), Ok(4));")] + /// ``` + #[unstable(feature = "int_from_ascii_radix", issue = "none")] + #[track_caller] + pub fn from_ascii_radix(src: &[u8], radix: u32) -> Result { + from_ascii_radix(src, radix) } /// Returns the number of ones in the binary representation of `self`.