2021-02-13 14:58:44 -06:00
|
|
|
//! Compare numeric types by exact bit value.
|
|
|
|
|
2021-01-03 15:09:26 -06:00
|
|
|
pub trait BitEq {
|
|
|
|
fn biteq(&self, other: &Self) -> bool;
|
|
|
|
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result;
|
|
|
|
}
|
|
|
|
|
2021-03-06 01:14:58 -06:00
|
|
|
impl BitEq for bool {
|
|
|
|
fn biteq(&self, other: &Self) -> bool {
|
|
|
|
self == other
|
|
|
|
}
|
|
|
|
|
|
|
|
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
|
|
|
|
write!(f, "{:?}", self)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-03 15:09:26 -06:00
|
|
|
macro_rules! impl_integer_biteq {
|
|
|
|
{ $($type:ty),* } => {
|
|
|
|
$(
|
|
|
|
impl BitEq for $type {
|
|
|
|
fn biteq(&self, other: &Self) -> bool {
|
|
|
|
self == other
|
|
|
|
}
|
|
|
|
|
|
|
|
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
|
|
|
|
write!(f, "{:?} ({:x})", self, self)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
)*
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
impl_integer_biteq! { u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize }
|
|
|
|
|
|
|
|
macro_rules! impl_float_biteq {
|
|
|
|
{ $($type:ty),* } => {
|
|
|
|
$(
|
|
|
|
impl BitEq for $type {
|
|
|
|
fn biteq(&self, other: &Self) -> bool {
|
|
|
|
if self.is_nan() && other.is_nan() {
|
|
|
|
true // exact nan bits don't matter
|
|
|
|
} else {
|
|
|
|
self.to_bits() == other.to_bits()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
|
|
|
|
write!(f, "{:?} ({:x})", self, self.to_bits())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
)*
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
impl_float_biteq! { f32, f64 }
|
|
|
|
|
2022-06-23 00:21:58 -05:00
|
|
|
impl<T> BitEq for *const T {
|
|
|
|
fn biteq(&self, other: &Self) -> bool {
|
|
|
|
self == other
|
|
|
|
}
|
|
|
|
|
|
|
|
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
|
|
|
|
write!(f, "{:?}", self)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T> BitEq for *mut T {
|
|
|
|
fn biteq(&self, other: &Self) -> bool {
|
|
|
|
self == other
|
|
|
|
}
|
|
|
|
|
|
|
|
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
|
|
|
|
write!(f, "{:?}", self)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-03 15:09:26 -06:00
|
|
|
impl<T: BitEq, const N: usize> BitEq for [T; N] {
|
|
|
|
fn biteq(&self, other: &Self) -> bool {
|
|
|
|
self.iter()
|
|
|
|
.zip(other.iter())
|
|
|
|
.fold(true, |value, (left, right)| value && left.biteq(right))
|
|
|
|
}
|
|
|
|
|
|
|
|
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
|
|
|
|
#[repr(transparent)]
|
|
|
|
struct Wrapper<'a, T: BitEq>(&'a T);
|
|
|
|
|
|
|
|
impl<T: BitEq> core::fmt::Debug for Wrapper<'_, T> {
|
|
|
|
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
|
|
|
|
self.0.fmt(f)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
f.debug_list()
|
|
|
|
.entries(self.iter().map(|x| Wrapper(x)))
|
|
|
|
.finish()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[doc(hidden)]
|
|
|
|
pub struct BitEqWrapper<'a, T>(pub &'a T);
|
|
|
|
|
|
|
|
impl<T: BitEq> PartialEq for BitEqWrapper<'_, T> {
|
|
|
|
fn eq(&self, other: &Self) -> bool {
|
|
|
|
self.0.biteq(other.0)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T: BitEq> core::fmt::Debug for BitEqWrapper<'_, T> {
|
|
|
|
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
|
|
|
|
self.0.fmt(f)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[macro_export]
|
|
|
|
macro_rules! prop_assert_biteq {
|
2021-03-07 23:48:18 -06:00
|
|
|
{ $a:expr, $b:expr $(,)? } => {
|
2021-01-03 15:09:26 -06:00
|
|
|
{
|
|
|
|
use $crate::biteq::BitEqWrapper;
|
|
|
|
let a = $a;
|
|
|
|
let b = $b;
|
|
|
|
proptest::prop_assert_eq!(BitEqWrapper(&a), BitEqWrapper(&b));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|