macro_rules! impl_bit_ops {
($primitive_ty:ty) => {
const BIT_COUNT: $primitive_ty = <$primitive_ty>::BITS as $primitive_ty;
#[track_caller]
const fn assert_in_range(n: $primitive_ty, inclusive: bool) {
if inclusive {
assert!(
n <= BIT_COUNT,
"bit position starts at 0 and should be less than or equal to `bitcount(type)`"
);
} else {
assert!(
n < BIT_COUNT,
"bit position starts at 0 and should be less than `bitcount(type)`"
);
}
}
#[doc = concat!("use bit_ops::bitops_", stringify!($primitive_ty), "::set_bit;")]
#[must_use]
#[inline]
pub const fn set_bit(base: $primitive_ty, bit: $primitive_ty) -> $primitive_ty {
assert_in_range(bit, false);
base | (1 << bit)
}
#[doc = concat!("use bit_ops::bitops_", stringify!($primitive_ty), "::set_bit_exact;")]
#[must_use]
#[inline]
pub const fn set_bit_exact(
base: $primitive_ty,
bit: $primitive_ty,
value: bool,
) -> $primitive_ty {
if value {
set_bit(base, bit)
} else {
clear_bit(base, bit)
}
}
#[doc = concat!("use bit_ops::bitops_", stringify!($primitive_ty), "::clear_bit;")]
#[must_use]
#[inline]
pub const fn clear_bit(base: $primitive_ty, bit: $primitive_ty) -> $primitive_ty {
assert_in_range(bit, false);
let negative_mask = !(1 << bit);
base & negative_mask
}
#[doc = concat!("use bit_ops::bitops_", stringify!($primitive_ty), "::is_set;")]
#[must_use]
#[inline]
pub const fn is_set(base: $primitive_ty, bit: $primitive_ty) -> bool {
get_bit(base, bit) == 1
}
#[doc = concat!("use bit_ops::bitops_", stringify!($primitive_ty), "::get_bit;")]
#[must_use]
#[inline]
pub const fn get_bit(base: $primitive_ty, bit: $primitive_ty) -> $primitive_ty {
assert_in_range(bit, false);
(base >> bit) & 1
}
#[doc = concat!("use bit_ops::bitops_", stringify!($primitive_ty), "::toggle_bit;")]
#[must_use]
#[inline]
pub const fn toggle_bit(val: $primitive_ty, bit: $primitive_ty) -> $primitive_ty {
toggle_bits(val, 1, bit)
}
#[doc = concat!("use bit_ops::bitops_", stringify!($primitive_ty), "::toggle_bits;")]
#[must_use]
#[inline]
pub const fn toggle_bits(
base: $primitive_ty,
bits: $primitive_ty,
shift: $primitive_ty,
) -> $primitive_ty {
assert_in_range(bits, true);
assert_in_range(shift, true);
let mask = create_mask(bits) << shift;
base ^ mask
}
#[doc = concat!("use bit_ops::bitops_", stringify!($primitive_ty), "::set_bits;")]
#[must_use]
#[inline]
pub const fn set_bits(
base: $primitive_ty,
value: $primitive_ty,
value_bits: $primitive_ty,
value_shift: $primitive_ty,
) -> $primitive_ty {
assert_in_range(value_bits, true);
assert_in_range(value_shift, true);
let value_mask = create_mask(value_bits);
let value = value & value_mask;
base | (value << value_shift)
}
#[doc = concat!("use bit_ops::bitops_", stringify!($primitive_ty), "::set_bits_n;")]
#[must_use]
#[inline]
pub const fn set_bits_n(
base: $primitive_ty,
ops: &[(
$primitive_ty, /* value */
$primitive_ty, /* value_bits */
$primitive_ty, /* value_shift */
)],
) -> $primitive_ty {
let mut base = base;
let mut i = 0;
while i < ops.len() {
let op = ops[i];
base = set_bits(base, op.0, op.1, op.2);
i += 1;
}
base
}
#[doc = concat!("use bit_ops::bitops_", stringify!($primitive_ty), "::set_bits_exact;")]
#[must_use]
#[inline]
pub const fn set_bits_exact(
base: $primitive_ty,
value: $primitive_ty,
value_bits: $primitive_ty,
value_shift: $primitive_ty,
) -> $primitive_ty {
let clear_mask = create_mask(value_bits) << value_shift;
let base = clear_bits(base, clear_mask);
set_bits(base, value, value_bits, value_shift)
}
#[doc = concat!("use bit_ops::bitops_", stringify!($primitive_ty), "::set_bits_n;")]
#[must_use]
#[inline]
pub const fn set_bits_exact_n(
base: $primitive_ty,
ops: &[(
$primitive_ty, /* value */
$primitive_ty, /* value_bits */
$primitive_ty, /* value_shift */
)],
) -> $primitive_ty {
let mut base = base;
let mut i = 0;
while i < ops.len() {
let op = ops[i];
base = set_bits_exact(base, op.0, op.1, op.2);
i += 1;
}
base
}
#[doc = concat!("use bit_ops::bitops_", stringify!($primitive_ty), "::clear_bits;")]
#[must_use]
#[inline]
pub const fn clear_bits(base: $primitive_ty, clear_mask: $primitive_ty) -> $primitive_ty {
base & !clear_mask
}
#[doc = concat!("use bit_ops::bitops_", stringify!($primitive_ty), "::highest_bit;")]
#[must_use]
#[inline]
pub const fn highest_bit(base: $primitive_ty) -> Option<$primitive_ty> {
if base == 0 {
None
} else {
let max_pos = BIT_COUNT - 1;
let bit = max_pos - (base.leading_zeros() as $primitive_ty);
Some(bit)
}
}
#[doc = concat!("use bit_ops::bitops_", stringify!($primitive_ty), "::lowest_bit;")]
#[must_use]
#[inline]
pub const fn lowest_bit(base: $primitive_ty) -> Option<$primitive_ty> {
if base == 0 {
None
} else {
Some(base.trailing_zeros() as $primitive_ty)
}
}
#[doc = concat!("use bit_ops::bitops_", stringify!($primitive_ty), "::get_bits;")]
#[must_use]
#[inline]
pub const fn get_bits(
base: $primitive_ty,
value_bits: $primitive_ty,
value_shift: $primitive_ty,
) -> $primitive_ty {
let mask = create_mask(value_bits);
(base >> value_shift) & mask
}
#[doc = concat!("use bit_ops::bitops_", stringify!($primitive_ty), "::create_mask;")]
#[must_use]
#[inline]
pub const fn create_mask(bits: $primitive_ty) -> $primitive_ty {
assert_in_range(bits, true);
if bits == 0 {
0
} else if bits == BIT_COUNT {
<$primitive_ty>::MAX
} else {
paste::paste! {
[< 1_ $primitive_ty >].wrapping_shl(bits as u32) - 1
}
}
}
};
}
macro_rules! impl_mod {
($primitive_ty:ty) => {
paste::paste! {
#[doc = concat!("[`", stringify!($primitive_ty), "`].")]
pub mod [< bitops _ $primitive_ty >] {
impl_bit_ops!($primitive_ty);
}
}
};
}