Skip to content

Commit a394d5e

Browse files
authored
Rollup merge of #154664 - okaneco:integer_cast_extras, r=scottmcm
core/num: Implement feature `integer_cast_extras` Tracking issue #154650 Accepted ACP rust-lang/libs-team#765 (comment) 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`
2 parents eb68787 + fd3a74d commit a394d5e

3 files changed

Lines changed: 186 additions & 0 deletions

File tree

library/core/src/num/imp/overflow_panic.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,3 +49,9 @@ pub(in crate::num) const fn shr() -> ! {
4949
pub(in crate::num) const fn shl() -> ! {
5050
panic!("attempt to shift left with overflow")
5151
}
52+
53+
#[cold]
54+
#[track_caller]
55+
pub(in crate::num) const fn cast_integer() -> ! {
56+
panic!("attempt to cast integer with overflow")
57+
}

library/core/src/num/int_macros.rs

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,94 @@ macro_rules! int_impl {
268268
self as $UnsignedT
269269
}
270270

271+
/// Saturating conversion of `self` to an unsigned integer of the same size.
272+
///
273+
/// Negative values are clamped to `0`.
274+
///
275+
/// For other kinds of unsigned integer casts, see
276+
/// [`cast_unsigned`](Self::cast_unsigned),
277+
/// [`checked_cast_unsigned`](Self::checked_cast_unsigned),
278+
/// or [`strict_cast_unsigned`](Self::strict_cast_unsigned).
279+
///
280+
/// # Examples
281+
///
282+
/// ```
283+
/// #![feature(integer_cast_extras)]
284+
#[doc = concat!("let n = ", stringify!($SelfT), "::MIN;")]
285+
///
286+
#[doc = concat!("assert_eq!(n.saturating_cast_unsigned(), 0", stringify!($UnsignedT), ");")]
287+
#[doc = concat!("assert_eq!(64", stringify!($SelfT), ".saturating_cast_unsigned(), 64", stringify!($UnsignedT), ");")]
288+
/// ```
289+
#[rustc_const_unstable(feature = "integer_cast_extras", issue = "154650")]
290+
#[unstable(feature = "integer_cast_extras", issue = "154650")]
291+
#[must_use = "this returns the result of the operation, \
292+
without modifying the original"]
293+
#[inline(always)]
294+
pub const fn saturating_cast_unsigned(self) -> $UnsignedT {
295+
if self >= 0 {
296+
self.cast_unsigned()
297+
} else {
298+
0
299+
}
300+
}
301+
302+
/// Checked conversion of `self` to an unsigned integer of the same size,
303+
/// returning `None` if `self` is negative.
304+
///
305+
/// For other kinds of unsigned integer casts, see
306+
/// [`cast_unsigned`](Self::cast_unsigned),
307+
/// [`saturating_cast_unsigned`](Self::saturating_cast_unsigned),
308+
/// or [`strict_cast_unsigned`](Self::strict_cast_unsigned).
309+
///
310+
/// # Examples
311+
///
312+
/// ```
313+
/// #![feature(integer_cast_extras)]
314+
#[doc = concat!("let n = ", stringify!($SelfT), "::MIN;")]
315+
///
316+
#[doc = concat!("assert_eq!(n.checked_cast_unsigned(), None);")]
317+
#[doc = concat!("assert_eq!(64", stringify!($SelfT), ".checked_cast_unsigned(), Some(64", stringify!($UnsignedT), "));")]
318+
/// ```
319+
#[rustc_const_unstable(feature = "integer_cast_extras", issue = "154650")]
320+
#[unstable(feature = "integer_cast_extras", issue = "154650")]
321+
#[must_use = "this returns the result of the operation, \
322+
without modifying the original"]
323+
#[inline(always)]
324+
pub const fn checked_cast_unsigned(self) -> Option<$UnsignedT> {
325+
if self >= 0 {
326+
Some(self.cast_unsigned())
327+
} else {
328+
None
329+
}
330+
}
331+
332+
/// Strict conversion of `self` to an unsigned integer of the same size,
333+
/// which panics if `self` is negative.
334+
///
335+
/// For other kinds of unsigned integer casts, see
336+
/// [`cast_unsigned`](Self::cast_unsigned),
337+
/// [`checked_cast_unsigned`](Self::checked_cast_unsigned),
338+
/// or [`saturating_cast_unsigned`](Self::saturating_cast_unsigned).
339+
///
340+
/// # Examples
341+
///
342+
/// ```should_panic
343+
/// #![feature(integer_cast_extras)]
344+
#[doc = concat!("let _ = ", stringify!($SelfT), "::MIN.strict_cast_unsigned();")]
345+
/// ```
346+
#[rustc_const_unstable(feature = "integer_cast_extras", issue = "154650")]
347+
#[unstable(feature = "integer_cast_extras", issue = "154650")]
348+
#[must_use = "this returns the result of the operation, \
349+
without modifying the original"]
350+
#[inline]
351+
#[track_caller]
352+
pub const fn strict_cast_unsigned(self) -> $UnsignedT {
353+
match self.checked_cast_unsigned() {
354+
Some(n) => n,
355+
None => imp::overflow_panic::cast_integer(),
356+
}
357+
}
358+
271359
/// Shifts the bits to the left by a specified amount, `n`,
272360
/// wrapping the truncated bits to the end of the resulting integer.
273361
///

library/core/src/num/uint_macros.rs

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,98 @@ macro_rules! uint_impl {
353353
self as $SignedT
354354
}
355355

356+
/// Saturating conversion of `self` to a signed integer of the same size.
357+
///
358+
/// The signed integer's maximum value is returned if `self` is larger
359+
/// than the maximum positive value representable by the signed integer.
360+
///
361+
/// For other kinds of signed integer casts, see
362+
/// [`cast_signed`](Self::cast_signed),
363+
/// [`checked_cast_signed`](Self::checked_cast_signed),
364+
/// or [`strict_cast_signed`](Self::strict_cast_signed).
365+
///
366+
/// # Examples
367+
///
368+
/// ```
369+
/// #![feature(integer_cast_extras)]
370+
#[doc = concat!("let n = ", stringify!($SelfT), "::MAX;")]
371+
///
372+
#[doc = concat!("assert_eq!(n.saturating_cast_signed(), ", stringify!($SignedT), "::MAX);")]
373+
#[doc = concat!("assert_eq!(64", stringify!($SelfT), ".saturating_cast_signed(), 64", stringify!($SignedT), ");")]
374+
/// ```
375+
#[rustc_const_unstable(feature = "integer_cast_extras", issue = "154650")]
376+
#[unstable(feature = "integer_cast_extras", issue = "154650")]
377+
#[must_use = "this returns the result of the operation, \
378+
without modifying the original"]
379+
#[inline(always)]
380+
pub const fn saturating_cast_signed(self) -> $SignedT {
381+
// Clamp to the signed integer max size, which is ActualT::MAX >> 1.
382+
if self <= <$SignedT>::MAX.cast_unsigned() {
383+
self.cast_signed()
384+
} else {
385+
<$SignedT>::MAX
386+
}
387+
}
388+
389+
/// Checked conversion of `self` to a signed integer of the same size,
390+
/// returning `None` if `self` is larger than the signed integer's
391+
/// maximum value.
392+
///
393+
/// For other kinds of signed integer casts, see
394+
/// [`cast_signed`](Self::cast_signed),
395+
/// [`saturating_cast_signed`](Self::saturating_cast_signed),
396+
/// or [`strict_cast_signed`](Self::strict_cast_signed).
397+
///
398+
/// # Examples
399+
///
400+
/// ```
401+
/// #![feature(integer_cast_extras)]
402+
#[doc = concat!("let n = ", stringify!($SelfT), "::MAX;")]
403+
///
404+
#[doc = concat!("assert_eq!(n.checked_cast_signed(), None);")]
405+
#[doc = concat!("assert_eq!(64", stringify!($SelfT), ".checked_cast_signed(), Some(64", stringify!($SignedT), "));")]
406+
/// ```
407+
#[rustc_const_unstable(feature = "integer_cast_extras", issue = "154650")]
408+
#[unstable(feature = "integer_cast_extras", issue = "154650")]
409+
#[must_use = "this returns the result of the operation, \
410+
without modifying the original"]
411+
#[inline(always)]
412+
pub const fn checked_cast_signed(self) -> Option<$SignedT> {
413+
if self <= <$SignedT>::MAX.cast_unsigned() {
414+
Some(self.cast_signed())
415+
} else {
416+
None
417+
}
418+
}
419+
420+
/// Strict conversion of `self` to a signed integer of the same size,
421+
/// which panics if `self` is larger than the signed integer's maximum
422+
/// value.
423+
///
424+
/// For other kinds of signed integer casts, see
425+
/// [`cast_signed`](Self::cast_signed),
426+
/// [`checked_cast_signed`](Self::checked_cast_signed),
427+
/// or [`saturating_cast_signed`](Self::saturating_cast_signed).
428+
///
429+
/// # Examples
430+
///
431+
/// ```should_panic
432+
/// #![feature(integer_cast_extras)]
433+
#[doc = concat!("let _ = ", stringify!($SelfT), "::MAX.strict_cast_signed();")]
434+
/// ```
435+
#[rustc_const_unstable(feature = "integer_cast_extras", issue = "154650")]
436+
#[unstable(feature = "integer_cast_extras", issue = "154650")]
437+
#[must_use = "this returns the result of the operation, \
438+
without modifying the original"]
439+
#[inline]
440+
#[track_caller]
441+
pub const fn strict_cast_signed(self) -> $SignedT {
442+
match self.checked_cast_signed() {
443+
Some(n) => n,
444+
None => imp::overflow_panic::cast_integer(),
445+
}
446+
}
447+
356448
/// Shifts the bits to the left by a specified amount, `n`,
357449
/// wrapping the truncated bits to the end of the resulting integer.
358450
///

0 commit comments

Comments
 (0)