From c9e408e3f853253d0e3c48ecfab6c3ed9179d55e Mon Sep 17 00:00:00 2001
From: Peter Jaszkowiak
Date: Sat, 27 Jul 2024 13:06:03 -0600
Subject: [PATCH] bitwise and bytewise methods on `NonZero`
---
library/core/src/num/nonzero.rs | 433 +++++++++++++++++++++++++++++++-
1 file changed, 430 insertions(+), 3 deletions(-)
diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs
index d80d3241b1eee..64985e216c451 100644
--- a/library/core/src/num/nonzero.rs
+++ b/library/core/src/num/nonzero.rs
@@ -455,6 +455,12 @@ macro_rules! nonzero_integer {
UnsignedPrimitive = $Uint:ty,
// Used in doc comments.
+ rot = $rot:literal,
+ rot_op = $rot_op:literal,
+ rot_result = $rot_result:literal,
+ swap_op = $swap_op:literal,
+ swapped = $swapped:literal,
+ reversed = $reversed:literal,
leading_zeros_test = $leading_zeros_test:expr,
) => {
/// An integer that is known not to equal zero.
@@ -604,6 +610,270 @@ macro_rules! nonzero_integer {
unsafe { NonZero::new_unchecked(self.get().count_ones()) }
}
+ /// Shifts the bits to the left by a specified amount, `n`,
+ /// wrapping the truncated bits to the end of the resulting integer.
+ ///
+ /// Please note this isn't the same operation as the `<<` shifting operator!
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// #![feature(nonzero_bitwise)]
+ /// # use std::num::NonZero;
+ /// #
+ /// # fn main() { test().unwrap(); }
+ /// # fn test() -> Option<()> {
+ #[doc = concat!("let n = NonZero::new(", $rot_op, stringify!($Int), ")?;")]
+ #[doc = concat!("let m = NonZero::new(", $rot_result, ")?;")]
+ ///
+ #[doc = concat!("assert_eq!(n.rotate_left(", $rot, "), m);")]
+ /// # Some(())
+ /// # }
+ /// ```
+ #[unstable(feature = "nonzero_bitwise", issue = "128281")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline(always)]
+ pub const fn rotate_left(self, n: u32) -> Self {
+ let result = self.get().rotate_left(n);
+ // SAFETY: Rotating bits preserves the property int > 0.
+ unsafe { Self::new_unchecked(result) }
+ }
+
+ /// Shifts the bits to the right by a specified amount, `n`,
+ /// wrapping the truncated bits to the beginning of the resulting
+ /// integer.
+ ///
+ /// Please note this isn't the same operation as the `>>` shifting operator!
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// #![feature(nonzero_bitwise)]
+ /// # use std::num::NonZero;
+ /// #
+ /// # fn main() { test().unwrap(); }
+ /// # fn test() -> Option<()> {
+ #[doc = concat!("let n = NonZero::new(", $rot_result, stringify!($Int), ")?;")]
+ #[doc = concat!("let m = NonZero::new(", $rot_op, ")?;")]
+ ///
+ #[doc = concat!("assert_eq!(n.rotate_right(", $rot, "), m);")]
+ /// # Some(())
+ /// # }
+ /// ```
+ #[unstable(feature = "nonzero_bitwise", issue = "128281")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline(always)]
+ pub const fn rotate_right(self, n: u32) -> Self {
+ let result = self.get().rotate_right(n);
+ // SAFETY: Rotating bits preserves the property int > 0.
+ unsafe { Self::new_unchecked(result) }
+ }
+
+ /// Reverses the byte order of the integer.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// #![feature(nonzero_bitwise)]
+ /// # use std::num::NonZero;
+ /// #
+ /// # fn main() { test().unwrap(); }
+ /// # fn test() -> Option<()> {
+ #[doc = concat!("let n = NonZero::new(", $swap_op, stringify!($Int), ")?;")]
+ /// let m = n.swap_bytes();
+ ///
+ #[doc = concat!("assert_eq!(m, NonZero::new(", $swapped, ")?);")]
+ /// # Some(())
+ /// # }
+ /// ```
+ #[unstable(feature = "nonzero_bitwise", issue = "128281")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline(always)]
+ pub const fn swap_bytes(self) -> Self {
+ let result = self.get().swap_bytes();
+ // SAFETY: Shuffling bytes preserves the property int > 0.
+ unsafe { Self::new_unchecked(result) }
+ }
+
+ /// Reverses the order of bits in the integer. The least significant bit becomes the most significant bit,
+ /// second least-significant bit becomes second most-significant bit, etc.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// #![feature(nonzero_bitwise)]
+ /// # use std::num::NonZero;
+ /// #
+ /// # fn main() { test().unwrap(); }
+ /// # fn test() -> Option<()> {
+ #[doc = concat!("let n = NonZero::new(", $swap_op, stringify!($Int), ")?;")]
+ /// let m = n.reverse_bits();
+ ///
+ #[doc = concat!("assert_eq!(m, NonZero::new(", $reversed, ")?);")]
+ /// # Some(())
+ /// # }
+ /// ```
+ #[unstable(feature = "nonzero_bitwise", issue = "128281")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline(always)]
+ pub const fn reverse_bits(self) -> Self {
+ let result = self.get().reverse_bits();
+ // SAFETY: Reversing bits preserves the property int > 0.
+ unsafe { Self::new_unchecked(result) }
+ }
+
+ /// Converts an integer from big endian to the target's endianness.
+ ///
+ /// On big endian this is a no-op. On little endian the bytes are
+ /// swapped.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// #![feature(nonzero_bitwise)]
+ /// # use std::num::NonZero;
+ #[doc = concat!("use std::num::", stringify!($Ty), ";")]
+ /// #
+ /// # fn main() { test().unwrap(); }
+ /// # fn test() -> Option<()> {
+ #[doc = concat!("let n = NonZero::new(0x1A", stringify!($Int), ")?;")]
+ ///
+ /// if cfg!(target_endian = "big") {
+ #[doc = concat!(" assert_eq!(", stringify!($Ty), "::from_be(n), n)")]
+ /// } else {
+ #[doc = concat!(" assert_eq!(", stringify!($Ty), "::from_be(n), n.swap_bytes())")]
+ /// }
+ /// # Some(())
+ /// # }
+ /// ```
+ #[unstable(feature = "nonzero_bitwise", issue = "128281")]
+ #[must_use]
+ #[inline(always)]
+ pub const fn from_be(x: Self) -> Self {
+ let result = $Int::from_be(x.get());
+ // SAFETY: Shuffling bytes preserves the property int > 0.
+ unsafe { Self::new_unchecked(result) }
+ }
+
+ /// Converts an integer from little endian to the target's endianness.
+ ///
+ /// On little endian this is a no-op. On big endian the bytes are
+ /// swapped.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// #![feature(nonzero_bitwise)]
+ /// # use std::num::NonZero;
+ #[doc = concat!("use std::num::", stringify!($Ty), ";")]
+ /// #
+ /// # fn main() { test().unwrap(); }
+ /// # fn test() -> Option<()> {
+ #[doc = concat!("let n = NonZero::new(0x1A", stringify!($Int), ")?;")]
+ ///
+ /// if cfg!(target_endian = "little") {
+ #[doc = concat!(" assert_eq!(", stringify!($Ty), "::from_le(n), n)")]
+ /// } else {
+ #[doc = concat!(" assert_eq!(", stringify!($Ty), "::from_le(n), n.swap_bytes())")]
+ /// }
+ /// # Some(())
+ /// # }
+ /// ```
+ #[unstable(feature = "nonzero_bitwise", issue = "128281")]
+ #[must_use]
+ #[inline(always)]
+ pub const fn from_le(x: Self) -> Self {
+ let result = $Int::from_le(x.get());
+ // SAFETY: Shuffling bytes preserves the property int > 0.
+ unsafe { Self::new_unchecked(result) }
+ }
+
+ /// Converts `self` to big endian from the target's endianness.
+ ///
+ /// On big endian this is a no-op. On little endian the bytes are
+ /// swapped.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// #![feature(nonzero_bitwise)]
+ /// # use std::num::NonZero;
+ /// #
+ /// # fn main() { test().unwrap(); }
+ /// # fn test() -> Option<()> {
+ #[doc = concat!("let n = NonZero::new(0x1A", stringify!($Int), ")?;")]
+ ///
+ /// if cfg!(target_endian = "big") {
+ /// assert_eq!(n.to_be(), n)
+ /// } else {
+ /// assert_eq!(n.to_be(), n.swap_bytes())
+ /// }
+ /// # Some(())
+ /// # }
+ /// ```
+ #[unstable(feature = "nonzero_bitwise", issue = "128281")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline(always)]
+ pub const fn to_be(self) -> Self {
+ let result = self.get().to_be();
+ // SAFETY: Shuffling bytes preserves the property int > 0.
+ unsafe { Self::new_unchecked(result) }
+ }
+
+ /// Converts `self` to little endian from the target's endianness.
+ ///
+ /// On little endian this is a no-op. On big endian the bytes are
+ /// swapped.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// #![feature(nonzero_bitwise)]
+ /// # use std::num::NonZero;
+ /// #
+ /// # fn main() { test().unwrap(); }
+ /// # fn test() -> Option<()> {
+ #[doc = concat!("let n = NonZero::new(0x1A", stringify!($Int), ")?;")]
+ ///
+ /// if cfg!(target_endian = "little") {
+ /// assert_eq!(n.to_le(), n)
+ /// } else {
+ /// assert_eq!(n.to_le(), n.swap_bytes())
+ /// }
+ /// # Some(())
+ /// # }
+ /// ```
+ #[unstable(feature = "nonzero_bitwise", issue = "128281")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline(always)]
+ pub const fn to_le(self) -> Self {
+ let result = self.get().to_le();
+ // SAFETY: Shuffling bytes preserves the property int > 0.
+ unsafe { Self::new_unchecked(result) }
+ }
+
nonzero_integer_signedness_dependent_methods! {
Primitive = $signedness $Int,
UnsignedPrimitive = $Uint,
@@ -826,22 +1096,54 @@ macro_rules! nonzero_integer {
nonzero_integer_signedness_dependent_impls!($signedness $Int);
};
- (Self = $Ty:ident, Primitive = unsigned $Int:ident $(,)?) => {
+ (
+ Self = $Ty:ident,
+ Primitive = unsigned $Int:ident,
+ rot = $rot:literal,
+ rot_op = $rot_op:literal,
+ rot_result = $rot_result:literal,
+ swap_op = $swap_op:literal,
+ swapped = $swapped:literal,
+ reversed = $reversed:literal,
+ $(,)?
+ ) => {
nonzero_integer! {
#[stable(feature = "nonzero", since = "1.28.0")]
Self = $Ty,
Primitive = unsigned $Int,
UnsignedPrimitive = $Int,
+ rot = $rot,
+ rot_op = $rot_op,
+ rot_result = $rot_result,
+ swap_op = $swap_op,
+ swapped = $swapped,
+ reversed = $reversed,
leading_zeros_test = concat!(stringify!($Int), "::MAX"),
}
};
- (Self = $Ty:ident, Primitive = signed $Int:ident, $($rest:tt)*) => {
+ (
+ Self = $Ty:ident,
+ Primitive = signed $Int:ident,
+ UnsignedPrimitive = $UInt:ident,
+ rot = $rot:literal,
+ rot_op = $rot_op:literal,
+ rot_result = $rot_result:literal,
+ swap_op = $swap_op:literal,
+ swapped = $swapped:literal,
+ reversed = $reversed:literal,
+ ) => {
nonzero_integer! {
#[stable(feature = "signed_nonzero", since = "1.34.0")]
Self = $Ty,
Primitive = signed $Int,
- $($rest)*
+ UnsignedPrimitive = $UInt,
+ rot = $rot,
+ rot_op = $rot_op,
+ rot_result = $rot_result,
+ swap_op = $swap_op,
+ swapped = $swapped,
+ reversed = $reversed,
leading_zeros_test = concat!("-1", stringify!($Int)),
}
};
@@ -1241,6 +1543,7 @@ macro_rules! nonzero_integer_signedness_dependent_methods {
/// assert_eq!(ten.isqrt(), three);
/// # Some(())
/// # }
+ /// ```
#[unstable(feature = "isqrt", issue = "116226")]
#[rustc_const_unstable(feature = "isqrt", issue = "116226")]
#[must_use = "this returns the result of the operation, \
@@ -1704,65 +2007,189 @@ macro_rules! sign_dependent_expr {
nonzero_integer! {
Self = NonZeroU8,
Primitive = unsigned u8,
+ rot = 2,
+ rot_op = "0x82",
+ rot_result = "0xa",
+ swap_op = "0x12",
+ swapped = "0x12",
+ reversed = "0x48",
}
nonzero_integer! {
Self = NonZeroU16,
Primitive = unsigned u16,
+ rot = 4,
+ rot_op = "0xa003",
+ rot_result = "0x3a",
+ swap_op = "0x1234",
+ swapped = "0x3412",
+ reversed = "0x2c48",
}
nonzero_integer! {
Self = NonZeroU32,
Primitive = unsigned u32,
+ rot = 8,
+ rot_op = "0x10000b3",
+ rot_result = "0xb301",
+ swap_op = "0x12345678",
+ swapped = "0x78563412",
+ reversed = "0x1e6a2c48",
}
nonzero_integer! {
Self = NonZeroU64,
Primitive = unsigned u64,
+ rot = 12,
+ rot_op = "0xaa00000000006e1",
+ rot_result = "0x6e10aa",
+ swap_op = "0x1234567890123456",
+ swapped = "0x5634129078563412",
+ reversed = "0x6a2c48091e6a2c48",
}
nonzero_integer! {
Self = NonZeroU128,
Primitive = unsigned u128,
+ rot = 16,
+ rot_op = "0x13f40000000000000000000000004f76",
+ rot_result = "0x4f7613f4",
+ swap_op = "0x12345678901234567890123456789012",
+ swapped = "0x12907856341290785634129078563412",
+ reversed = "0x48091e6a2c48091e6a2c48091e6a2c48",
+}
+
+#[cfg(target_pointer_width = "16")]
+nonzero_integer! {
+ Self = NonZeroUsize,
+ Primitive = unsigned usize,
+ rot = 4,
+ rot_op = "0xa003",
+ rot_result = "0x3a",
+ swap_op = "0x1234",
+ swapped = "0x3412",
+ reversed = "0x2c48",
}
+#[cfg(target_pointer_width = "32")]
nonzero_integer! {
Self = NonZeroUsize,
Primitive = unsigned usize,
+ rot = 8,
+ rot_op = "0x10000b3",
+ rot_result = "0xb301",
+ swap_op = "0x12345678",
+ swapped = "0x78563412",
+ reversed = "0x1e6a2c48",
+}
+
+#[cfg(target_pointer_width = "64")]
+nonzero_integer! {
+ Self = NonZeroUsize,
+ Primitive = unsigned usize,
+ rot = 12,
+ rot_op = "0xaa00000000006e1",
+ rot_result = "0x6e10aa",
+ swap_op = "0x1234567890123456",
+ swapped = "0x5634129078563412",
+ reversed = "0x6a2c48091e6a2c48",
}
nonzero_integer! {
Self = NonZeroI8,
Primitive = signed i8,
UnsignedPrimitive = u8,
+ rot = 2,
+ rot_op = "-0x7e",
+ rot_result = "0xa",
+ swap_op = "0x12",
+ swapped = "0x12",
+ reversed = "0x48",
}
nonzero_integer! {
Self = NonZeroI16,
Primitive = signed i16,
UnsignedPrimitive = u16,
+ rot = 4,
+ rot_op = "-0x5ffd",
+ rot_result = "0x3a",
+ swap_op = "0x1234",
+ swapped = "0x3412",
+ reversed = "0x2c48",
}
nonzero_integer! {
Self = NonZeroI32,
Primitive = signed i32,
UnsignedPrimitive = u32,
+ rot = 8,
+ rot_op = "0x10000b3",
+ rot_result = "0xb301",
+ swap_op = "0x12345678",
+ swapped = "0x78563412",
+ reversed = "0x1e6a2c48",
}
nonzero_integer! {
Self = NonZeroI64,
Primitive = signed i64,
UnsignedPrimitive = u64,
+ rot = 12,
+ rot_op = "0xaa00000000006e1",
+ rot_result = "0x6e10aa",
+ swap_op = "0x1234567890123456",
+ swapped = "0x5634129078563412",
+ reversed = "0x6a2c48091e6a2c48",
}
nonzero_integer! {
Self = NonZeroI128,
Primitive = signed i128,
UnsignedPrimitive = u128,
+ rot = 16,
+ rot_op = "0x13f40000000000000000000000004f76",
+ rot_result = "0x4f7613f4",
+ swap_op = "0x12345678901234567890123456789012",
+ swapped = "0x12907856341290785634129078563412",
+ reversed = "0x48091e6a2c48091e6a2c48091e6a2c48",
+}
+
+#[cfg(target_pointer_width = "16")]
+nonzero_integer! {
+ Self = NonZeroIsize,
+ Primitive = signed isize,
+ UnsignedPrimitive = usize,
+ rot = 4,
+ rot_op = "-0x5ffd",
+ rot_result = "0x3a",
+ swap_op = "0x1234",
+ swapped = "0x3412",
+ reversed = "0x2c48",
+}
+
+#[cfg(target_pointer_width = "32")]
+nonzero_integer! {
+ Self = NonZeroIsize,
+ Primitive = signed isize,
+ UnsignedPrimitive = usize,
+ rot = 8,
+ rot_op = "0x10000b3",
+ rot_result = "0xb301",
+ swap_op = "0x12345678",
+ swapped = "0x78563412",
+ reversed = "0x1e6a2c48",
}
+#[cfg(target_pointer_width = "64")]
nonzero_integer! {
Self = NonZeroIsize,
Primitive = signed isize,
UnsignedPrimitive = usize,
+ rot = 12,
+ rot_op = "0xaa00000000006e1",
+ rot_result = "0x6e10aa",
+ swap_op = "0x1234567890123456",
+ swapped = "0x5634129078563412",
+ reversed = "0x6a2c48091e6a2c48",
}