bitwise and bytewise methods on `NonZero`

This commit is contained in:
Peter Jaszkowiak 2024-07-27 13:06:03 -06:00
parent 8fe0c753f2
commit c9e408e3f8
1 changed files with 430 additions and 3 deletions

View File

@ -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",
}