Skip to content

Commit 775108a

Browse files
committed
feat: Add TryFromIntError::kind and IntErrorKind::NotAPowerOfTwo
1 parent 8317fef commit 775108a

6 files changed

Lines changed: 121 additions & 32 deletions

File tree

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
@@ -272,7 +272,7 @@ macro_rules! impl_try_from_lower_bounded {
272272
if u >= 0 {
273273
Ok(u as Self)
274274
} else {
275-
Err(TryFromIntError(()))
275+
Err(TryFromIntError(IntErrorKind::NegOverflow))
276276
}
277277
}
278278
}
@@ -293,7 +293,7 @@ macro_rules! impl_try_from_upper_bounded {
293293
#[inline]
294294
fn try_from(u: $source) -> Result<Self, Self::Error> {
295295
if u > (Self::MAX as $source) {
296-
Err(TryFromIntError(()))
296+
Err(TryFromIntError(IntErrorKind::PosOverflow))
297297
} else {
298298
Ok(u as Self)
299299
}
@@ -317,8 +317,10 @@ macro_rules! impl_try_from_both_bounded {
317317
fn try_from(u: $source) -> Result<Self, Self::Error> {
318318
let min = Self::MIN as $source;
319319
let max = Self::MAX as $source;
320-
if u < min || u > max {
321-
Err(TryFromIntError(()))
320+
if u < min {
321+
Err(TryFromIntError(IntErrorKind::NegOverflow))
322+
} else if u > max {
323+
Err(TryFromIntError(IntErrorKind::PosOverflow))
322324
} else {
323325
Ok(u as Self)
324326
}
@@ -329,7 +331,7 @@ macro_rules! impl_try_from_both_bounded {
329331

330332
/// Implement `TryFrom<integer>` for `bool`
331333
macro_rules! impl_try_from_integer_for_bool {
332-
($($int:ty)+) => {$(
334+
($signedness:ident $($int:ty)+) => {$(
333335
#[stable(feature = "bool_try_from_int", since = "1.95.0")]
334336
#[rustc_const_unstable(feature = "const_convert", issue = "143773")]
335337
impl const TryFrom<$int> for bool {
@@ -349,10 +351,23 @@ macro_rules! impl_try_from_integer_for_bool {
349351
/// ```
350352
#[inline]
351353
fn try_from(i: $int) -> Result<Self, Self::Error> {
352-
match i {
353-
0 => Ok(false),
354-
1 => Ok(true),
355-
_ => Err(TryFromIntError(())),
354+
sign_dependent_expr!{
355+
$signedness ?
356+
if signed {
357+
match i {
358+
0 => Ok(false),
359+
1 => Ok(true),
360+
..0 => Err(TryFromIntError(IntErrorKind::NegOverflow)),
361+
2.. => Err(TryFromIntError(IntErrorKind::PosOverflow)),
362+
}
363+
}
364+
if unsigned {
365+
match i {
366+
0 => Ok(false),
367+
1 => Ok(true),
368+
2.. => Err(TryFromIntError(IntErrorKind::PosOverflow)),
369+
}
370+
}
356371
}
357372
}
358373
}
@@ -366,8 +381,8 @@ macro_rules! rev {
366381
}
367382

368383
// integer -> bool
369-
impl_try_from_integer_for_bool!(u128 u64 u32 u16 u8);
370-
impl_try_from_integer_for_bool!(i128 i64 i32 i16 i8);
384+
impl_try_from_integer_for_bool!(unsigned u128 u64 u32 u16 u8);
385+
impl_try_from_integer_for_bool!(signed i128 i64 i32 i16 i8);
371386

372387
// unsigned integer -> unsigned integer
373388
impl_try_from_upper_bounded!(u16 => u8);
@@ -405,7 +420,7 @@ impl_try_from_lower_bounded!(isize => usize);
405420

406421
#[cfg(target_pointer_width = "16")]
407422
mod ptr_try_from_impls {
408-
use super::TryFromIntError;
423+
use super::{IntErrorKind, TryFromIntError};
409424

410425
impl_try_from_upper_bounded!(usize => u8);
411426
impl_try_from_unbounded!(usize => u16, u32, u64, u128);
@@ -427,7 +442,7 @@ mod ptr_try_from_impls {
427442

428443
#[cfg(target_pointer_width = "32")]
429444
mod ptr_try_from_impls {
430-
use super::TryFromIntError;
445+
use super::{IntErrorKind, TryFromIntError};
431446

432447
impl_try_from_upper_bounded!(usize => u8, u16);
433448
impl_try_from_unbounded!(usize => u32, u64, u128);
@@ -452,7 +467,7 @@ mod ptr_try_from_impls {
452467

453468
#[cfg(target_pointer_width = "64")]
454469
mod ptr_try_from_impls {
455-
use super::TryFromIntError;
470+
use super::{IntErrorKind, TryFromIntError};
456471

457472
impl_try_from_upper_bounded!(usize => u8, u16, u32);
458473
impl_try_from_unbounded!(usize => u64, u128);
@@ -550,7 +565,7 @@ macro_rules! impl_nonzero_int_try_from_int {
550565
#[doc = concat!("to <code>[NonZero]\\<[", stringify!($Int), "]></code>.")]
551566
#[inline]
552567
fn try_from(value: $Int) -> Result<Self, Self::Error> {
553-
Self::new(value).ok_or(TryFromIntError(()))
568+
Self::new(value).ok_or(TryFromIntError(IntErrorKind::Zero))
554569
}
555570
}
556571
};

library/core/src/mem/alignment.rs

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

282282
#[inline]
283283
fn try_from(align: usize) -> Result<Alignment, Self::Error> {
284-
Self::new(align).ok_or(num::TryFromIntError(()))
284+
Self::new(align).ok_or(num::TryFromIntError(num::IntErrorKind::NotAPowerOfTwo))
285285
}
286286
}
287287

library/core/src/num/error.rs

Lines changed: 19 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,14 @@ 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 = "try_from_int_error_kind", issue = "153978")]
122+
// Also, #[unstable(feature = "ptr_alignment_type", issue = "102070")]
123+
NotAPowerOfTwo,
110124
}
111125

112126
impl ParseIntError {
@@ -128,6 +142,7 @@ impl fmt::Display for ParseIntError {
128142
IntErrorKind::PosOverflow => "number too large to fit in target type",
129143
IntErrorKind::NegOverflow => "number too small to fit in target type",
130144
IntErrorKind::Zero => "number would be zero for non-zero type",
145+
IntErrorKind::NotAPowerOfTwo => unreachable!(),
131146
}
132147
.fmt(f)
133148
}

library/coretests/tests/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@
119119
#![feature(trusted_random_access)]
120120
#![feature(try_blocks)]
121121
#![feature(try_find)]
122+
#![feature(try_from_int_error_kind)]
122123
#![feature(try_trait_v2)]
123124
#![feature(type_info)]
124125
#![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
@@ -374,6 +374,43 @@ fn test_f32f64() {
374374
assert!(nan.is_nan());
375375
}
376376

377+
/// Conversions where $source can be represented as bool.
378+
macro_rules! test_impl_try_from_integer_to_bool {
379+
($fn_name:ident, $source:ty) => {
380+
#[test]
381+
fn $fn_name() {
382+
let max: $source = <$source>::MAX;
383+
let min: $source = <$source>::MIN;
384+
let zero: $source = 0;
385+
let one: $source = 1;
386+
let two: $source = 2;
387+
assert_eq!(bool::try_from(max).unwrap_err().kind(), &IntErrorKind::PosOverflow);
388+
if min != 0 {
389+
assert_eq!(bool::try_from(min).unwrap_err().kind(), &IntErrorKind::NegOverflow);
390+
assert_eq!(
391+
bool::try_from(zero - 1).unwrap_err().kind(),
392+
&IntErrorKind::NegOverflow
393+
);
394+
}
395+
assert_eq!(bool::try_from(zero).unwrap(), false);
396+
assert_eq!(bool::try_from(one).unwrap(), true);
397+
assert_eq!(bool::try_from(two).unwrap_err().kind(), &IntErrorKind::PosOverflow);
398+
}
399+
};
400+
}
401+
402+
test_impl_try_from_integer_to_bool! { test_try_u8bool, u8 }
403+
test_impl_try_from_integer_to_bool! { test_try_u16bool, u16 }
404+
test_impl_try_from_integer_to_bool! { test_try_u32bool, u32 }
405+
test_impl_try_from_integer_to_bool! { test_try_u64bool, u64 }
406+
test_impl_try_from_integer_to_bool! { test_try_u128bool, u128 }
407+
408+
test_impl_try_from_integer_to_bool! { test_try_i8bool, i8 }
409+
test_impl_try_from_integer_to_bool! { test_try_i16bool, i16 }
410+
test_impl_try_from_integer_to_bool! { test_try_i32bool, i32 }
411+
test_impl_try_from_integer_to_bool! { test_try_i64bool, i64 }
412+
test_impl_try_from_integer_to_bool! { test_try_i128bool, i128 }
413+
377414
/// Conversions where the full width of $source can be represented as $target
378415
macro_rules! test_impl_try_from_always_ok {
379416
($fn_name:ident, $source:ty, $target: ty) => {
@@ -497,9 +534,15 @@ macro_rules! test_impl_try_from_signed_to_unsigned_upper_ok {
497534
let zero: $source = 0;
498535
let neg_one: $source = -1;
499536
assert_eq!(<$target as TryFrom<$source>>::try_from(max).unwrap(), max as $target);
500-
assert!(<$target as TryFrom<$source>>::try_from(min).is_err());
537+
assert_eq!(
538+
<$target as TryFrom<$source>>::try_from(min).unwrap_err().kind(),
539+
&IntErrorKind::NegOverflow
540+
);
501541
assert_eq!(<$target as TryFrom<$source>>::try_from(zero).unwrap(), zero as $target);
502-
assert!(<$target as TryFrom<$source>>::try_from(neg_one).is_err());
542+
assert_eq!(
543+
<$target as TryFrom<$source>>::try_from(neg_one).unwrap_err().kind(),
544+
&IntErrorKind::NegOverflow
545+
);
503546
}
504547
};
505548
}
@@ -560,7 +603,10 @@ macro_rules! test_impl_try_from_unsigned_to_signed_upper_err {
560603
let max = <$source>::MAX;
561604
let min = <$source>::MIN;
562605
let zero: $source = 0;
563-
assert!(<$target as TryFrom<$source>>::try_from(max).is_err());
606+
assert_eq!(
607+
<$target as TryFrom<$source>>::try_from(max).unwrap_err().kind(),
608+
&IntErrorKind::PosOverflow
609+
);
564610
assert_eq!(<$target as TryFrom<$source>>::try_from(min).unwrap(), min as $target);
565611
assert_eq!(<$target as TryFrom<$source>>::try_from(zero).unwrap(), zero as $target);
566612
}
@@ -623,9 +669,15 @@ macro_rules! test_impl_try_from_same_sign_err {
623669
let zero: $source = 0;
624670
let t_max = <$target>::MAX;
625671
let t_min = <$target>::MIN;
626-
assert!(<$target as TryFrom<$source>>::try_from(max).is_err());
672+
assert_eq!(
673+
<$target as TryFrom<$source>>::try_from(max).unwrap_err().kind(),
674+
&IntErrorKind::PosOverflow
675+
);
627676
if min != 0 {
628-
assert!(<$target as TryFrom<$source>>::try_from(min).is_err());
677+
assert_eq!(
678+
<$target as TryFrom<$source>>::try_from(min).unwrap_err().kind(),
679+
&IntErrorKind::NegOverflow
680+
);
629681
}
630682
assert_eq!(<$target as TryFrom<$source>>::try_from(zero).unwrap(), zero as $target);
631683
assert_eq!(
@@ -712,8 +764,14 @@ macro_rules! test_impl_try_from_signed_to_unsigned_err {
712764
let zero: $source = 0;
713765
let t_max = <$target>::MAX;
714766
let t_min = <$target>::MIN;
715-
assert!(<$target as TryFrom<$source>>::try_from(max).is_err());
716-
assert!(<$target as TryFrom<$source>>::try_from(min).is_err());
767+
assert_eq!(
768+
<$target as TryFrom<$source>>::try_from(max).unwrap_err().kind(),
769+
&IntErrorKind::PosOverflow
770+
);
771+
assert_eq!(
772+
<$target as TryFrom<$source>>::try_from(min).unwrap_err().kind(),
773+
&IntErrorKind::NegOverflow
774+
);
717775
assert_eq!(<$target as TryFrom<$source>>::try_from(zero).unwrap(), zero as $target);
718776
assert_eq!(
719777
<$target as TryFrom<$source>>::try_from(t_max as $source).unwrap(),

0 commit comments

Comments
 (0)