|
1 | 1 | use crate::num::{IntErrorKind, TryFromIntError}; |
2 | 2 |
|
| 3 | +mod private { |
| 4 | + /// This trait being unreachable from outside the crate |
| 5 | + /// prevents other implementations of the `FloatToInt` trait, |
| 6 | + /// which allows potentially adding more trait methods after the trait is `#[stable]`. |
| 7 | + #[unstable(feature = "convert_float_to_int", issue = "67057")] |
| 8 | + pub trait Sealed {} |
| 9 | + |
| 10 | + /// This trait being unreachable from outside the crate prevents other |
| 11 | + /// implementations of the integer cast traits. |
| 12 | + /// |
| 13 | + /// `Cast<T> : SealedCast<T>` avoids the orphan rule, which would otherwise |
| 14 | + /// allow e.g. implementing `Cast<Foo>` for `u8`. |
| 15 | + #[unstable(feature = "integer_casts", issue = "157388")] |
| 16 | + pub trait SealedCast<T>: Sealed {} |
| 17 | + |
| 18 | + #[unstable(feature = "integer_casts", issue = "157388")] |
| 19 | + impl<T: Sealed, U: Sealed> SealedCast<T> for U {} |
| 20 | + |
| 21 | + macro_rules! impl_sealed_int { |
| 22 | + ([$($T:ty),*]) => {$( |
| 23 | + #[unstable(feature = "integer_casts", issue = "157388")] |
| 24 | + impl Sealed for $T { } |
| 25 | + )*}; |
| 26 | + } |
| 27 | + |
| 28 | + impl_sealed_int!([u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize]); |
| 29 | +} |
| 30 | + |
3 | 31 | /// Supporting trait for inherent methods of `f32` and `f64` such as `to_int_unchecked`. |
4 | 32 | /// Typically doesn’t need to be used directly. |
5 | 33 | #[unstable(feature = "convert_float_to_int", issue = "67057")] |
@@ -630,3 +658,98 @@ impl_nonzero_int_try_from_nonzero_int!(i32 => u8, u16, u32, u64, u128, usize); |
630 | 658 | impl_nonzero_int_try_from_nonzero_int!(i64 => u8, u16, u32, u64, u128, usize); |
631 | 659 | impl_nonzero_int_try_from_nonzero_int!(i128 => u8, u16, u32, u64, u128, usize); |
632 | 660 | impl_nonzero_int_try_from_nonzero_int!(isize => u8, u16, u32, u64, u128, usize); |
| 661 | + |
| 662 | +/// Conversion between integers, wrapping around or saturating at the target type's boundaries. |
| 663 | +#[unstable(feature = "integer_casts", issue = "157388")] |
| 664 | +#[rustc_const_unstable(feature = "integer_casts", issue = "157388")] |
| 665 | +pub const trait BoundedCastFromInt<T>: private::SealedCast<T> + Sized { |
| 666 | + /// Converts `value` to this type, wrapping around at the boundary of the type. |
| 667 | + #[unstable(feature = "integer_casts", issue = "157388")] |
| 668 | + fn wrapping_cast_from(value: T) -> Self; |
| 669 | + |
| 670 | + /// Converts `value` to this type, saturating at the numeric bounds instead of overflowing. |
| 671 | + #[unstable(feature = "integer_casts", issue = "157388")] |
| 672 | + fn saturating_cast_from(value: T) -> Self; |
| 673 | +} |
| 674 | + |
| 675 | +/// Fallible conversion between integers. |
| 676 | +#[unstable(feature = "integer_casts", issue = "157388")] |
| 677 | +#[rustc_const_unstable(feature = "integer_casts", issue = "157388")] |
| 678 | +pub const trait CheckedCastFromInt<T>: private::SealedCast<T> + Sized { |
| 679 | + /// Converts `value` to this type, returning `None` if overflow would have occurred. |
| 680 | + #[unstable(feature = "integer_casts", issue = "157388")] |
| 681 | + fn checked_cast_from(value: T) -> Option<Self>; |
| 682 | + |
| 683 | + /// Converts `value` to this type, assuming overflow cannot occur. |
| 684 | + /// |
| 685 | + /// # Safety |
| 686 | + /// |
| 687 | + /// This results in undefined behavior when `value` will overflow when |
| 688 | + /// converted to this type. |
| 689 | + #[unstable(feature = "integer_casts", issue = "157388")] |
| 690 | + unsafe fn unchecked_cast_from(value: T) -> Self; |
| 691 | + |
| 692 | + /// Converts `value` to this type, panicking on overflow. |
| 693 | + /// |
| 694 | + /// # Panics |
| 695 | + /// |
| 696 | + /// This function will always panic on overflow, regardless of whether overflow checks are enabled. |
| 697 | + #[unstable(feature = "integer_casts", issue = "157388")] |
| 698 | + fn strict_cast_from(value: T) -> Self; |
| 699 | +} |
| 700 | + |
| 701 | +macro_rules! impl_int_cast { |
| 702 | + ($Src:ty as [$($Dst:ty),*]) => {$( |
| 703 | + #[unstable(feature = "integer_casts", issue = "157388")] |
| 704 | + #[rustc_const_unstable(feature = "integer_casts", issue = "157388")] |
| 705 | + impl const CheckedCastFromInt<$Src> for $Dst { |
| 706 | + #[inline] |
| 707 | + fn checked_cast_from(value: $Src) -> Option<Self> { |
| 708 | + value.try_into().ok() |
| 709 | + } |
| 710 | + |
| 711 | + #[inline(always)] |
| 712 | + unsafe fn unchecked_cast_from(value: $Src) -> Self { |
| 713 | + // SAFETY: the safety contract must be upheld by the caller. |
| 714 | + unsafe { value.try_into().unwrap_unchecked() } |
| 715 | + } |
| 716 | + |
| 717 | + #[inline] |
| 718 | + #[track_caller] |
| 719 | + fn strict_cast_from(value: $Src) -> Self { |
| 720 | + match value.try_into() { |
| 721 | + Ok(x) => x, |
| 722 | + Err(_) => core::num::imp::overflow_panic::cast_integer() |
| 723 | + } |
| 724 | + } |
| 725 | + } |
| 726 | + |
| 727 | + #[unstable(feature = "integer_casts", issue = "157388")] |
| 728 | + #[rustc_const_unstable(feature = "integer_casts", issue = "157388")] |
| 729 | + impl const BoundedCastFromInt<$Src> for $Dst { |
| 730 | + #[inline(always)] |
| 731 | + fn wrapping_cast_from(value: $Src) -> Self { |
| 732 | + value as Self |
| 733 | + } |
| 734 | + |
| 735 | + #[inline] |
| 736 | + #[allow(unused_comparisons)] |
| 737 | + #[allow(irrefutable_let_patterns)] |
| 738 | + fn saturating_cast_from(value: $Src) -> Self { |
| 739 | + if let Ok(x) = value.try_into() { |
| 740 | + return x; |
| 741 | + } |
| 742 | + |
| 743 | + if value < 0 { <$Dst>::MIN } else { <$Dst>::MAX } |
| 744 | + } |
| 745 | + } |
| 746 | + )*}; |
| 747 | +} |
| 748 | + |
| 749 | +macro_rules! impl_all_int_casts { |
| 750 | + ([$($Src:ty),*]) => {$( |
| 751 | + impl_int_cast!($Src as [u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize]); |
| 752 | + )*}; |
| 753 | +} |
| 754 | + |
| 755 | +impl_all_int_casts!([u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize]); |
0 commit comments