1pub trait BitEq {
4 fn biteq(&self, other: &Self) -> bool;
5 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result;
6}
7
8impl BitEq for bool {
9 fn biteq(&self, other: &Self) -> bool {
10 self == other
11 }
12
13 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
14 write!(f, "{:?}", self)
15 }
16}
17
18macro_rules! impl_integer_biteq {
19 { $($type:ty),* } => {
20 $(
21 impl BitEq for $type {
22 fn biteq(&self, other: &Self) -> bool {
23 self == other
24 }
25
26 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
27 write!(f, "{:?} ({:x})", self, self)
28 }
29 }
30 )*
31 };
32}
33
34impl_integer_biteq! { u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize }
35
36macro_rules! impl_float_biteq {
37 { $($type:ty),* } => {
38 $(
39 impl BitEq for $type {
40 fn biteq(&self, other: &Self) -> bool {
41 if self.is_nan() && other.is_nan() {
42 true } else {
44 self.to_bits() == other.to_bits()
45 }
46 }
47
48 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
49 write!(f, "{:?} ({:x})", self, self.to_bits())
50 }
51 }
52 )*
53 };
54}
55
56impl_float_biteq! { f32, f64 }
57
58impl<T> BitEq for *const T {
59 fn biteq(&self, other: &Self) -> bool {
60 self == other
61 }
62
63 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
64 write!(f, "{:?}", self)
65 }
66}
67
68impl<T> BitEq for *mut T {
69 fn biteq(&self, other: &Self) -> bool {
70 self == other
71 }
72
73 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
74 write!(f, "{:?}", self)
75 }
76}
77
78impl<T: BitEq, const N: usize> BitEq for [T; N] {
79 fn biteq(&self, other: &Self) -> bool {
80 self.iter()
81 .zip(other.iter())
82 .fold(true, |value, (left, right)| value && left.biteq(right))
83 }
84
85 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
86 #[repr(transparent)]
87 struct Wrapper<'a, T: BitEq>(&'a T);
88
89 impl<T: BitEq> core::fmt::Debug for Wrapper<'_, T> {
90 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
91 self.0.fmt(f)
92 }
93 }
94
95 f.debug_list()
96 .entries(self.iter().map(|x| Wrapper(x)))
97 .finish()
98 }
99}
100
101#[doc(hidden)]
102pub struct BitEqWrapper<'a, T>(pub &'a T);
103
104impl<T: BitEq> PartialEq for BitEqWrapper<'_, T> {
105 fn eq(&self, other: &Self) -> bool {
106 self.0.biteq(other.0)
107 }
108}
109
110impl<T: BitEq> core::fmt::Debug for BitEqWrapper<'_, T> {
111 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
112 self.0.fmt(f)
113 }
114}
115
116#[doc(hidden)]
117pub struct BitEqEitherWrapper<'a, T>(pub &'a T, pub &'a T);
118
119impl<T: BitEq> PartialEq<BitEqEitherWrapper<'_, T>> for BitEqWrapper<'_, T> {
120 fn eq(&self, other: &BitEqEitherWrapper<'_, T>) -> bool {
121 self.0.biteq(other.0) || self.0.biteq(other.1)
122 }
123}
124
125impl<T: BitEq> core::fmt::Debug for BitEqEitherWrapper<'_, T> {
126 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
127 if self.0.biteq(self.1) {
128 self.0.fmt(f)
129 } else {
130 self.0.fmt(f)?;
131 write!(f, " or ")?;
132 self.1.fmt(f)
133 }
134 }
135}
136
137#[macro_export]
138macro_rules! prop_assert_biteq {
139 { $a:expr, $b:expr $(,)? } => {
140 {
141 use $crate::biteq::BitEqWrapper;
142 let a = $a;
143 let b = $b;
144 proptest::prop_assert_eq!(BitEqWrapper(&a), BitEqWrapper(&b));
145 }
146 };
147 { $a:expr, $b:expr, $c:expr $(,)? } => {
148 {
149 use $crate::biteq::{BitEqWrapper, BitEqEitherWrapper};
150 let a = $a;
151 let b = $b;
152 let c = $c;
153 proptest::prop_assert_eq!(BitEqWrapper(&a), BitEqEitherWrapper(&b, &c));
154 }
155 };
156}