Skip to content

Commit 82e9d9e

Browse files
committed
from_u32(0) can just be default()
1 parent 72a5e7e commit 82e9d9e

File tree

3 files changed

+57
-16
lines changed

3 files changed

+57
-16
lines changed

library/core/src/num/mod.rs

+10-15
Original file line numberDiff line numberDiff line change
@@ -969,9 +969,8 @@ pub enum FpCategory {
969969
}
970970

971971
#[doc(hidden)]
972-
trait FromStrRadixHelper: PartialOrd + Copy {
972+
trait FromStrRadixHelper: PartialOrd + Copy + Default {
973973
const MIN: Self;
974-
fn from_u32(u: u32) -> Self;
975974
fn checked_mul(&self, other: u32) -> Option<Self>;
976975
fn checked_sub(&self, other: u32) -> Option<Self>;
977976
fn checked_add(&self, other: u32) -> Option<Self>;
@@ -997,8 +996,6 @@ macro_rules! impl_helper_for {
997996
($($t:ty)*) => ($(impl FromStrRadixHelper for $t {
998997
const MIN: Self = Self::MIN;
999998
#[inline]
1000-
fn from_u32(u: u32) -> Self { u as Self }
1001-
#[inline]
1002999
fn checked_mul(&self, other: u32) -> Option<Self> {
10031000
Self::checked_mul(*self, other as Self)
10041001
}
@@ -1035,8 +1032,14 @@ macro_rules! impl_helper_for {
10351032
}
10361033
impl_helper_for! { i8 i16 i32 i64 i128 isize u8 u16 u32 u64 u128 usize }
10371034

1035+
/// Determins if a string of text of that length of that radix could be guaranteed to be
1036+
/// stored in the given type T.
1037+
/// Note that if the radix is known to the compiler, it is just the check of digits.len that
1038+
/// is done at runtime.
1039+
#[doc(hidden)]
10381040
#[inline(always)]
1039-
pub(crate) fn can_not_overflow<T>(radix: u32, is_signed_ty: bool, digits:&[u8]) -> bool {
1041+
#[unstable(issue = "none", feature = "std_internals")]
1042+
pub fn can_not_overflow<T>(radix: u32, is_signed_ty: bool, digits: &[u8]) -> bool {
10401043
radix <= 16 && digits.len() <= mem::size_of::<T>() * 2 - is_signed_ty as usize
10411044
}
10421045

@@ -1054,7 +1057,7 @@ fn from_str_radix<T: FromStrRadixHelper>(src: &str, radix: u32) -> Result<T, Par
10541057
return Err(PIE { kind: Empty });
10551058
}
10561059

1057-
let is_signed_ty = T::from_u32(0) > T::MIN;
1060+
let is_signed_ty = T::default() > T::MIN;
10581061

10591062
// all valid digits are ascii, so we will just iterate over the utf8 bytes
10601063
// and cast them to chars. .to_digit() will safely return None for anything
@@ -1071,7 +1074,7 @@ fn from_str_radix<T: FromStrRadixHelper>(src: &str, radix: u32) -> Result<T, Par
10711074
_ => (true, src),
10721075
};
10731076

1074-
let mut result = T::from_u32(0);
1077+
let mut result = T::default();
10751078

10761079
if can_not_overflow::<T>(radix, is_signed_ty, digits) {
10771080
// SAFETY: If the len of the str is short compared to the range of the type
@@ -1127,11 +1130,3 @@ fn from_str_radix<T: FromStrRadixHelper>(src: &str, radix: u32) -> Result<T, Par
11271130
}
11281131
Ok(result)
11291132
}
1130-
1131-
mod tests {
1132-
#[test]
1133-
fn test_can_not_overflow() {
1134-
assert_eq!(can_not_overflow::<i8>(10, true, "99".as_bytes()), true);
1135-
assert_eq!(can_not_overflow::<i8>(10, true, "129".as_bytes()), false);
1136-
}
1137-
}

library/core/tests/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@
5555
#![feature(numfmt)]
5656
#![feature(step_trait)]
5757
#![feature(str_internals)]
58+
#![feature(std_internals)]
5859
#![feature(test)]
5960
#![feature(trusted_len)]
6061
#![feature(try_blocks)]

library/core/tests/num/mod.rs

+46-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use core::cmp::PartialEq;
22
use core::convert::{TryFrom, TryInto};
33
use core::fmt::Debug;
44
use core::marker::Copy;
5-
use core::num::{IntErrorKind, ParseIntError, TryFromIntError};
5+
use core::num::{can_not_overflow, IntErrorKind, ParseIntError, TryFromIntError};
66
use core::ops::{Add, Div, Mul, Rem, Sub};
77
use core::option::Option;
88
use core::option::Option::None;
@@ -120,6 +120,51 @@ fn test_int_from_str_overflow() {
120120
test_parse::<i64>("-9223372036854775809", Err(IntErrorKind::NegOverflow));
121121
}
122122

123+
#[test]
124+
fn test_can_not_overflow() {
125+
// Not currently in std lib (issue: #27728)
126+
fn format_radix<T>(mut x: T, radix: T) -> String
127+
where
128+
T: std::ops::Rem<Output = T>,
129+
T: std::ops::Div<Output = T>,
130+
T: std::cmp::PartialEq,
131+
T: std::default::Default,
132+
T: Copy,
133+
T: Default,
134+
u32: TryFrom<T>,
135+
{
136+
let mut result = vec![];
137+
138+
loop {
139+
let m = x % radix;
140+
x = x / radix;
141+
result.push(
142+
std::char::from_digit(m.try_into().ok().unwrap(), radix.try_into().ok().unwrap())
143+
.unwrap(),
144+
);
145+
if x == T::default() {
146+
break;
147+
}
148+
}
149+
result.into_iter().rev().collect()
150+
}
151+
152+
macro_rules! check {
153+
($($t:ty)*) => ($(
154+
for base in 2..=36 {
155+
let num = (<$t>::MAX as u128) + 1;
156+
157+
// Calcutate the string length for the smallest overflowing number:
158+
let max_len_string = format_radix(num, base as u128);
159+
// Ensure that that string length is deemed to potentially overflow:
160+
assert_eq!(can_not_overflow::<$t>(base, <$t>::default() > <$t>::MIN, max_len_string.as_bytes()), false);
161+
}
162+
)*)
163+
}
164+
165+
check! { i8 i16 i32 i64 i128 isize usize u8 u16 u32 u64 }
166+
}
167+
123168
#[test]
124169
fn test_leading_plus() {
125170
test_parse::<u8>("+127", Ok(127));

0 commit comments

Comments
 (0)