Skip to content

Commit 989926f

Browse files
committed
feat: Add TryFromIntError::kind and IntErrorKind::NotAPowerOfTwo
1 parent 3645249 commit 989926f

File tree

6 files changed

+120
-32
lines changed

6 files changed

+120
-32
lines changed

library/core/src/convert/num.rs

Lines changed: 31 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::num::TryFromIntError;
1+
use crate::num::{IntErrorKind, TryFromIntError};
22

33
mod private {
44
/// This trait being unreachable from outside the crate
@@ -274,7 +274,7 @@ macro_rules! impl_try_from_lower_bounded {
274274
if u >= 0 {
275275
Ok(u as Self)
276276
} else {
277-
Err(TryFromIntError(()))
277+
Err(TryFromIntError(IntErrorKind::NegOverflow))
278278
}
279279
}
280280
}
@@ -295,7 +295,7 @@ macro_rules! impl_try_from_upper_bounded {
295295
#[inline]
296296
fn try_from(u: $source) -> Result<Self, Self::Error> {
297297
if u > (Self::MAX as $source) {
298-
Err(TryFromIntError(()))
298+
Err(TryFromIntError(IntErrorKind::PosOverflow))
299299
} else {
300300
Ok(u as Self)
301301
}
@@ -319,8 +319,10 @@ macro_rules! impl_try_from_both_bounded {
319319
fn try_from(u: $source) -> Result<Self, Self::Error> {
320320
let min = Self::MIN as $source;
321321
let max = Self::MAX as $source;
322-
if u < min || u > max {
323-
Err(TryFromIntError(()))
322+
if u < min {
323+
Err(TryFromIntError(IntErrorKind::NegOverflow))
324+
} else if u > max {
325+
Err(TryFromIntError(IntErrorKind::PosOverflow))
324326
} else {
325327
Ok(u as Self)
326328
}
@@ -331,7 +333,7 @@ macro_rules! impl_try_from_both_bounded {
331333

332334
/// Implement `TryFrom<integer>` for `bool`
333335
macro_rules! impl_try_from_integer_for_bool {
334-
($($int:ty)+) => {$(
336+
($signedness:ident $($int:ty)+) => {$(
335337
#[stable(feature = "try_from", since = "1.34.0")]
336338
#[rustc_const_unstable(feature = "const_convert", issue = "143773")]
337339
impl const TryFrom<$int> for bool {
@@ -351,10 +353,23 @@ macro_rules! impl_try_from_integer_for_bool {
351353
/// ```
352354
#[inline]
353355
fn try_from(i: $int) -> Result<Self, Self::Error> {
354-
match i {
355-
0 => Ok(false),
356-
1 => Ok(true),
357-
_ => Err(TryFromIntError(())),
356+
sign_dependent_expr!{
357+
$signedness ?
358+
if signed {
359+
match i {
360+
0 => Ok(false),
361+
1 => Ok(true),
362+
..0 => Err(TryFromIntError(IntErrorKind::NegOverflow)),
363+
2.. => Err(TryFromIntError(IntErrorKind::PosOverflow)),
364+
}
365+
}
366+
if unsigned {
367+
match i {
368+
0 => Ok(false),
369+
1 => Ok(true),
370+
2.. => Err(TryFromIntError(IntErrorKind::PosOverflow)),
371+
}
372+
}
358373
}
359374
}
360375
}
@@ -368,8 +383,8 @@ macro_rules! rev {
368383
}
369384

370385
// integer -> bool
371-
impl_try_from_integer_for_bool!(u128 u64 u32 u16 u8);
372-
impl_try_from_integer_for_bool!(i128 i64 i32 i16 i8);
386+
impl_try_from_integer_for_bool!(unsigned u128 u64 u32 u16 u8);
387+
impl_try_from_integer_for_bool!(signed i128 i64 i32 i16 i8);
373388

374389
// unsigned integer -> unsigned integer
375390
impl_try_from_upper_bounded!(u16 => u8);
@@ -407,7 +422,7 @@ impl_try_from_lower_bounded!(isize => usize);
407422

408423
#[cfg(target_pointer_width = "16")]
409424
mod ptr_try_from_impls {
410-
use super::TryFromIntError;
425+
use super::{IntErrorKind, TryFromIntError};
411426

412427
impl_try_from_upper_bounded!(usize => u8);
413428
impl_try_from_unbounded!(usize => u16, u32, u64, u128);
@@ -429,7 +444,7 @@ mod ptr_try_from_impls {
429444

430445
#[cfg(target_pointer_width = "32")]
431446
mod ptr_try_from_impls {
432-
use super::TryFromIntError;
447+
use super::{IntErrorKind, TryFromIntError};
433448

434449
impl_try_from_upper_bounded!(usize => u8, u16);
435450
impl_try_from_unbounded!(usize => u32, u64, u128);
@@ -454,7 +469,7 @@ mod ptr_try_from_impls {
454469

455470
#[cfg(target_pointer_width = "64")]
456471
mod ptr_try_from_impls {
457-
use super::TryFromIntError;
472+
use super::{IntErrorKind, TryFromIntError};
458473

459474
impl_try_from_upper_bounded!(usize => u8, u16, u32);
460475
impl_try_from_unbounded!(usize => u64, u128);
@@ -552,7 +567,7 @@ macro_rules! impl_nonzero_int_try_from_int {
552567
#[doc = concat!("to <code>[NonZero]\\<[", stringify!($Int), "]></code>.")]
553568
#[inline]
554569
fn try_from(value: $Int) -> Result<Self, Self::Error> {
555-
Self::new(value).ok_or(TryFromIntError(()))
570+
Self::new(value).ok_or(TryFromIntError(IntErrorKind::Zero))
556571
}
557572
}
558573
};

library/core/src/num/error.rs

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,16 @@ use crate::fmt;
77
/// The error type returned when a checked integral type conversion fails.
88
#[stable(feature = "try_from", since = "1.34.0")]
99
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
10-
pub struct TryFromIntError(pub(crate) ());
10+
pub struct TryFromIntError(pub(crate) IntErrorKind);
11+
12+
impl TryFromIntError {
13+
/// Outputs the detailed cause of converting an integer failing.
14+
#[must_use]
15+
#[unstable(feature = "try_from_int_error_kind", issue = "153978")]
16+
pub const fn kind(&self) -> &IntErrorKind {
17+
&self.0
18+
}
19+
}
1120

1221
#[stable(feature = "try_from", since = "1.34.0")]
1322
impl fmt::Display for TryFromIntError {
@@ -66,7 +75,8 @@ pub struct ParseIntError {
6675
pub(super) kind: IntErrorKind,
6776
}
6877

69-
/// Enum to store the various types of errors that can cause parsing an integer to fail.
78+
/// Enum to store the various types of errors that can cause parsing or converting an
79+
/// integer to fail.
7080
///
7181
/// # Example
7282
///
@@ -103,10 +113,13 @@ pub enum IntErrorKind {
103113
NegOverflow,
104114
/// Value was Zero
105115
///
106-
/// This variant will be emitted when the parsing string has a value of zero, which
107-
/// would be illegal for non-zero types.
116+
/// This variant will be emitted when the parsing string or the converting integer
117+
/// has a value of zero, which would be illegal for non-zero types.
108118
#[stable(feature = "int_error_matching", since = "1.55.0")]
109119
Zero,
120+
/// Value is not a power of two.
121+
#[unstable(feature = "ptr_alignment_type", issue = "102070")]
122+
NotAPowerOfTwo,
110123
}
111124

112125
impl ParseIntError {
@@ -128,6 +141,7 @@ impl fmt::Display for ParseIntError {
128141
IntErrorKind::PosOverflow => "number too large to fit in target type",
129142
IntErrorKind::NegOverflow => "number too small to fit in target type",
130143
IntErrorKind::Zero => "number would be zero for non-zero type",
144+
IntErrorKind::NotAPowerOfTwo => unreachable!(),
131145
}
132146
.fmt(f)
133147
}

library/core/src/ptr/alignment.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -268,7 +268,7 @@ impl const TryFrom<usize> for Alignment {
268268

269269
#[inline]
270270
fn try_from(align: usize) -> Result<Alignment, Self::Error> {
271-
Self::new(align).ok_or(num::TryFromIntError(()))
271+
Self::new(align).ok_or(num::TryFromIntError(num::IntErrorKind::NotAPowerOfTwo))
272272
}
273273
}
274274

library/coretests/tests/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@
115115
#![feature(trusted_random_access)]
116116
#![feature(try_blocks)]
117117
#![feature(try_find)]
118+
#![feature(try_from_int_error_kind)]
118119
#![feature(try_trait_v2)]
119120
#![feature(type_info)]
120121
#![feature(uint_bit_width)]

library/coretests/tests/nonzero.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -282,11 +282,11 @@ fn test_nonzero_from_int_on_success() {
282282

283283
#[test]
284284
fn test_nonzero_from_int_on_err() {
285-
assert!(NonZero::<u8>::try_from(0).is_err());
286-
assert!(NonZero::<u32>::try_from(0).is_err());
285+
assert_eq!(NonZero::<u8>::try_from(0).unwrap_err().kind(), &IntErrorKind::Zero);
286+
assert_eq!(NonZero::<u32>::try_from(0).unwrap_err().kind(), &IntErrorKind::Zero);
287287

288-
assert!(NonZero::<i8>::try_from(0).is_err());
289-
assert!(NonZero::<i32>::try_from(0).is_err());
288+
assert_eq!(NonZero::<i8>::try_from(0).unwrap_err().kind(), &IntErrorKind::Zero);
289+
assert_eq!(NonZero::<i32>::try_from(0).unwrap_err().kind(), &IntErrorKind::Zero);
290290
}
291291

292292
#[test]

library/coretests/tests/num/mod.rs

Lines changed: 65 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,43 @@ fn test_f32f64() {
371371
assert!(nan.is_nan());
372372
}
373373

374+
/// Conversions where $source can be represented as bool.
375+
macro_rules! test_impl_try_from_integer_to_bool {
376+
($fn_name:ident, $source:ty) => {
377+
#[test]
378+
fn $fn_name() {
379+
let max: $source = <$source>::MAX;
380+
let min: $source = <$source>::MIN;
381+
let zero: $source = 0;
382+
let one: $source = 1;
383+
let two: $source = 2;
384+
assert_eq!(bool::try_from(max).unwrap_err().kind(), &IntErrorKind::PosOverflow);
385+
if min != 0 {
386+
assert_eq!(bool::try_from(min).unwrap_err().kind(), &IntErrorKind::NegOverflow);
387+
assert_eq!(
388+
bool::try_from(zero - 1).unwrap_err().kind(),
389+
&IntErrorKind::NegOverflow
390+
);
391+
}
392+
assert_eq!(bool::try_from(zero).unwrap(), false);
393+
assert_eq!(bool::try_from(one).unwrap(), true);
394+
assert_eq!(bool::try_from(two).unwrap_err().kind(), &IntErrorKind::PosOverflow);
395+
}
396+
};
397+
}
398+
399+
test_impl_try_from_integer_to_bool! { test_try_u8bool, u8 }
400+
test_impl_try_from_integer_to_bool! { test_try_u16bool, u16 }
401+
test_impl_try_from_integer_to_bool! { test_try_u32bool, u32 }
402+
test_impl_try_from_integer_to_bool! { test_try_u64bool, u64 }
403+
test_impl_try_from_integer_to_bool! { test_try_u128bool, u128 }
404+
405+
test_impl_try_from_integer_to_bool! { test_try_i8bool, i8 }
406+
test_impl_try_from_integer_to_bool! { test_try_i16bool, i16 }
407+
test_impl_try_from_integer_to_bool! { test_try_i32bool, i32 }
408+
test_impl_try_from_integer_to_bool! { test_try_i64bool, i64 }
409+
test_impl_try_from_integer_to_bool! { test_try_i128bool, i128 }
410+
374411
/// Conversions where the full width of $source can be represented as $target
375412
macro_rules! test_impl_try_from_always_ok {
376413
($fn_name:ident, $source:ty, $target: ty) => {
@@ -494,9 +531,15 @@ macro_rules! test_impl_try_from_signed_to_unsigned_upper_ok {
494531
let zero: $source = 0;
495532
let neg_one: $source = -1;
496533
assert_eq!(<$target as TryFrom<$source>>::try_from(max).unwrap(), max as $target);
497-
assert!(<$target as TryFrom<$source>>::try_from(min).is_err());
534+
assert_eq!(
535+
<$target as TryFrom<$source>>::try_from(min).unwrap_err().kind(),
536+
&IntErrorKind::NegOverflow
537+
);
498538
assert_eq!(<$target as TryFrom<$source>>::try_from(zero).unwrap(), zero as $target);
499-
assert!(<$target as TryFrom<$source>>::try_from(neg_one).is_err());
539+
assert_eq!(
540+
<$target as TryFrom<$source>>::try_from(neg_one).unwrap_err().kind(),
541+
&IntErrorKind::NegOverflow
542+
);
500543
}
501544
};
502545
}
@@ -557,7 +600,10 @@ macro_rules! test_impl_try_from_unsigned_to_signed_upper_err {
557600
let max = <$source>::MAX;
558601
let min = <$source>::MIN;
559602
let zero: $source = 0;
560-
assert!(<$target as TryFrom<$source>>::try_from(max).is_err());
603+
assert_eq!(
604+
<$target as TryFrom<$source>>::try_from(max).unwrap_err().kind(),
605+
&IntErrorKind::PosOverflow
606+
);
561607
assert_eq!(<$target as TryFrom<$source>>::try_from(min).unwrap(), min as $target);
562608
assert_eq!(<$target as TryFrom<$source>>::try_from(zero).unwrap(), zero as $target);
563609
}
@@ -620,9 +666,15 @@ macro_rules! test_impl_try_from_same_sign_err {
620666
let zero: $source = 0;
621667
let t_max = <$target>::MAX;
622668
let t_min = <$target>::MIN;
623-
assert!(<$target as TryFrom<$source>>::try_from(max).is_err());
669+
assert_eq!(
670+
<$target as TryFrom<$source>>::try_from(max).unwrap_err().kind(),
671+
&IntErrorKind::PosOverflow
672+
);
624673
if min != 0 {
625-
assert!(<$target as TryFrom<$source>>::try_from(min).is_err());
674+
assert_eq!(
675+
<$target as TryFrom<$source>>::try_from(min).unwrap_err().kind(),
676+
&IntErrorKind::NegOverflow
677+
);
626678
}
627679
assert_eq!(<$target as TryFrom<$source>>::try_from(zero).unwrap(), zero as $target);
628680
assert_eq!(
@@ -709,8 +761,14 @@ macro_rules! test_impl_try_from_signed_to_unsigned_err {
709761
let zero: $source = 0;
710762
let t_max = <$target>::MAX;
711763
let t_min = <$target>::MIN;
712-
assert!(<$target as TryFrom<$source>>::try_from(max).is_err());
713-
assert!(<$target as TryFrom<$source>>::try_from(min).is_err());
764+
assert_eq!(
765+
<$target as TryFrom<$source>>::try_from(max).unwrap_err().kind(),
766+
&IntErrorKind::PosOverflow
767+
);
768+
assert_eq!(
769+
<$target as TryFrom<$source>>::try_from(min).unwrap_err().kind(),
770+
&IntErrorKind::NegOverflow
771+
);
714772
assert_eq!(<$target as TryFrom<$source>>::try_from(zero).unwrap(), zero as $target);
715773
assert_eq!(
716774
<$target as TryFrom<$source>>::try_from(t_max as $source).unwrap(),

0 commit comments

Comments
 (0)