mirror of
https://github.com/rust-lang/rust.git
synced 2026-04-26 13:01:27 +03:00
Rollup merge of #154664 - okaneco:integer_cast_extras, r=scottmcm
core/num: Implement feature `integer_cast_extras` Tracking issue https://github.com/rust-lang/rust/issues/154650 Accepted ACP https://github.com/rust-lang/libs-team/issues/765#issuecomment-4164285847 Implement `saturating`, `checked`, and `strict` casting between signed and unsigned integer primitives of the same bit-width. Add `cast_integer` panic function to `overflow_panic.rs`
This commit is contained in:
@@ -49,3 +49,9 @@ pub(in crate::num) const fn shr() -> ! {
|
||||
pub(in crate::num) const fn shl() -> ! {
|
||||
panic!("attempt to shift left with overflow")
|
||||
}
|
||||
|
||||
#[cold]
|
||||
#[track_caller]
|
||||
pub(in crate::num) const fn cast_integer() -> ! {
|
||||
panic!("attempt to cast integer with overflow")
|
||||
}
|
||||
|
||||
@@ -268,6 +268,94 @@ pub const fn cast_unsigned(self) -> $UnsignedT {
|
||||
self as $UnsignedT
|
||||
}
|
||||
|
||||
/// Saturating conversion of `self` to an unsigned integer of the same size.
|
||||
///
|
||||
/// Negative values are clamped to `0`.
|
||||
///
|
||||
/// For other kinds of unsigned integer casts, see
|
||||
/// [`cast_unsigned`](Self::cast_unsigned),
|
||||
/// [`checked_cast_unsigned`](Self::checked_cast_unsigned),
|
||||
/// or [`strict_cast_unsigned`](Self::strict_cast_unsigned).
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(integer_cast_extras)]
|
||||
#[doc = concat!("let n = ", stringify!($SelfT), "::MIN;")]
|
||||
///
|
||||
#[doc = concat!("assert_eq!(n.saturating_cast_unsigned(), 0", stringify!($UnsignedT), ");")]
|
||||
#[doc = concat!("assert_eq!(64", stringify!($SelfT), ".saturating_cast_unsigned(), 64", stringify!($UnsignedT), ");")]
|
||||
/// ```
|
||||
#[rustc_const_unstable(feature = "integer_cast_extras", issue = "154650")]
|
||||
#[unstable(feature = "integer_cast_extras", issue = "154650")]
|
||||
#[must_use = "this returns the result of the operation, \
|
||||
without modifying the original"]
|
||||
#[inline(always)]
|
||||
pub const fn saturating_cast_unsigned(self) -> $UnsignedT {
|
||||
if self >= 0 {
|
||||
self.cast_unsigned()
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
/// Checked conversion of `self` to an unsigned integer of the same size,
|
||||
/// returning `None` if `self` is negative.
|
||||
///
|
||||
/// For other kinds of unsigned integer casts, see
|
||||
/// [`cast_unsigned`](Self::cast_unsigned),
|
||||
/// [`saturating_cast_unsigned`](Self::saturating_cast_unsigned),
|
||||
/// or [`strict_cast_unsigned`](Self::strict_cast_unsigned).
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(integer_cast_extras)]
|
||||
#[doc = concat!("let n = ", stringify!($SelfT), "::MIN;")]
|
||||
///
|
||||
#[doc = concat!("assert_eq!(n.checked_cast_unsigned(), None);")]
|
||||
#[doc = concat!("assert_eq!(64", stringify!($SelfT), ".checked_cast_unsigned(), Some(64", stringify!($UnsignedT), "));")]
|
||||
/// ```
|
||||
#[rustc_const_unstable(feature = "integer_cast_extras", issue = "154650")]
|
||||
#[unstable(feature = "integer_cast_extras", issue = "154650")]
|
||||
#[must_use = "this returns the result of the operation, \
|
||||
without modifying the original"]
|
||||
#[inline(always)]
|
||||
pub const fn checked_cast_unsigned(self) -> Option<$UnsignedT> {
|
||||
if self >= 0 {
|
||||
Some(self.cast_unsigned())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Strict conversion of `self` to an unsigned integer of the same size,
|
||||
/// which panics if `self` is negative.
|
||||
///
|
||||
/// For other kinds of unsigned integer casts, see
|
||||
/// [`cast_unsigned`](Self::cast_unsigned),
|
||||
/// [`checked_cast_unsigned`](Self::checked_cast_unsigned),
|
||||
/// or [`saturating_cast_unsigned`](Self::saturating_cast_unsigned).
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```should_panic
|
||||
/// #![feature(integer_cast_extras)]
|
||||
#[doc = concat!("let _ = ", stringify!($SelfT), "::MIN.strict_cast_unsigned();")]
|
||||
/// ```
|
||||
#[rustc_const_unstable(feature = "integer_cast_extras", issue = "154650")]
|
||||
#[unstable(feature = "integer_cast_extras", issue = "154650")]
|
||||
#[must_use = "this returns the result of the operation, \
|
||||
without modifying the original"]
|
||||
#[inline]
|
||||
#[track_caller]
|
||||
pub const fn strict_cast_unsigned(self) -> $UnsignedT {
|
||||
match self.checked_cast_unsigned() {
|
||||
Some(n) => n,
|
||||
None => imp::overflow_panic::cast_integer(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Shifts the bits to the left by a specified amount, `n`,
|
||||
/// wrapping the truncated bits to the end of the resulting integer.
|
||||
///
|
||||
|
||||
@@ -353,6 +353,98 @@ pub const fn cast_signed(self) -> $SignedT {
|
||||
self as $SignedT
|
||||
}
|
||||
|
||||
/// Saturating conversion of `self` to a signed integer of the same size.
|
||||
///
|
||||
/// The signed integer's maximum value is returned if `self` is larger
|
||||
/// than the maximum positive value representable by the signed integer.
|
||||
///
|
||||
/// For other kinds of signed integer casts, see
|
||||
/// [`cast_signed`](Self::cast_signed),
|
||||
/// [`checked_cast_signed`](Self::checked_cast_signed),
|
||||
/// or [`strict_cast_signed`](Self::strict_cast_signed).
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(integer_cast_extras)]
|
||||
#[doc = concat!("let n = ", stringify!($SelfT), "::MAX;")]
|
||||
///
|
||||
#[doc = concat!("assert_eq!(n.saturating_cast_signed(), ", stringify!($SignedT), "::MAX);")]
|
||||
#[doc = concat!("assert_eq!(64", stringify!($SelfT), ".saturating_cast_signed(), 64", stringify!($SignedT), ");")]
|
||||
/// ```
|
||||
#[rustc_const_unstable(feature = "integer_cast_extras", issue = "154650")]
|
||||
#[unstable(feature = "integer_cast_extras", issue = "154650")]
|
||||
#[must_use = "this returns the result of the operation, \
|
||||
without modifying the original"]
|
||||
#[inline(always)]
|
||||
pub const fn saturating_cast_signed(self) -> $SignedT {
|
||||
// Clamp to the signed integer max size, which is ActualT::MAX >> 1.
|
||||
if self <= <$SignedT>::MAX.cast_unsigned() {
|
||||
self.cast_signed()
|
||||
} else {
|
||||
<$SignedT>::MAX
|
||||
}
|
||||
}
|
||||
|
||||
/// Checked conversion of `self` to a signed integer of the same size,
|
||||
/// returning `None` if `self` is larger than the signed integer's
|
||||
/// maximum value.
|
||||
///
|
||||
/// For other kinds of signed integer casts, see
|
||||
/// [`cast_signed`](Self::cast_signed),
|
||||
/// [`saturating_cast_signed`](Self::saturating_cast_signed),
|
||||
/// or [`strict_cast_signed`](Self::strict_cast_signed).
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(integer_cast_extras)]
|
||||
#[doc = concat!("let n = ", stringify!($SelfT), "::MAX;")]
|
||||
///
|
||||
#[doc = concat!("assert_eq!(n.checked_cast_signed(), None);")]
|
||||
#[doc = concat!("assert_eq!(64", stringify!($SelfT), ".checked_cast_signed(), Some(64", stringify!($SignedT), "));")]
|
||||
/// ```
|
||||
#[rustc_const_unstable(feature = "integer_cast_extras", issue = "154650")]
|
||||
#[unstable(feature = "integer_cast_extras", issue = "154650")]
|
||||
#[must_use = "this returns the result of the operation, \
|
||||
without modifying the original"]
|
||||
#[inline(always)]
|
||||
pub const fn checked_cast_signed(self) -> Option<$SignedT> {
|
||||
if self <= <$SignedT>::MAX.cast_unsigned() {
|
||||
Some(self.cast_signed())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Strict conversion of `self` to a signed integer of the same size,
|
||||
/// which panics if `self` is larger than the signed integer's maximum
|
||||
/// value.
|
||||
///
|
||||
/// For other kinds of signed integer casts, see
|
||||
/// [`cast_signed`](Self::cast_signed),
|
||||
/// [`checked_cast_signed`](Self::checked_cast_signed),
|
||||
/// or [`saturating_cast_signed`](Self::saturating_cast_signed).
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```should_panic
|
||||
/// #![feature(integer_cast_extras)]
|
||||
#[doc = concat!("let _ = ", stringify!($SelfT), "::MAX.strict_cast_signed();")]
|
||||
/// ```
|
||||
#[rustc_const_unstable(feature = "integer_cast_extras", issue = "154650")]
|
||||
#[unstable(feature = "integer_cast_extras", issue = "154650")]
|
||||
#[must_use = "this returns the result of the operation, \
|
||||
without modifying the original"]
|
||||
#[inline]
|
||||
#[track_caller]
|
||||
pub const fn strict_cast_signed(self) -> $SignedT {
|
||||
match self.checked_cast_signed() {
|
||||
Some(n) => n,
|
||||
None => imp::overflow_panic::cast_integer(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Shifts the bits to the left by a specified amount, `n`,
|
||||
/// wrapping the truncated bits to the end of the resulting integer.
|
||||
///
|
||||
|
||||
Reference in New Issue
Block a user