1use std::any::Any;
12use std::any::TypeId;
13use std::marker::PhantomData;
14
15pub struct PartialEqAny<'a> {
21 type_id: TypeId,
22 cmp: unsafe fn(*const (), *const ()) -> bool,
23 val: *const (),
24 _marker: PhantomData<&'a dyn Any>,
25}
26
27impl<'a> PartialEqAny<'a> {
28 #[inline]
29 pub fn new<A: PartialEq + 'static>(a: &'a A) -> Self {
30 PartialEqAny {
31 type_id: TypeId::of::<A>(),
32 cmp: |this, other| {
33 let this = unsafe { &*(this as *const A) };
36 let other = unsafe { &*(other as *const A) };
37 this == other
38 },
39 val: a as *const A as *const (),
40 _marker: PhantomData,
41 }
42 }
43
44 #[inline]
46 pub fn type_id(&self) -> TypeId {
47 self.type_id
48 }
49
50 #[inline]
52 pub fn always_false() -> Self {
53 struct AlwaysFalse;
54
55 impl PartialEq for AlwaysFalse {
56 fn eq(&self, _other: &Self) -> bool {
57 false
58 }
59 }
60
61 PartialEqAny::new(&AlwaysFalse)
62 }
63}
64
65impl<'a> PartialEq for PartialEqAny<'a> {
66 #[inline]
67 fn eq(&self, other: &PartialEqAny<'a>) -> bool {
68 self.type_id == other.type_id && unsafe { (self.cmp)(self.val, other.val) }
69 }
70}
71
72#[cfg(test)]
73#[allow(clippy::bool_assert_comparison)]
74mod tests {
75 use crate::eq::PartialEqAny;
76
77 struct Wrap<T>(T);
78
79 impl<T: PartialEq + 'static> Wrap<T> {
80 fn token(&self) -> PartialEqAny<'_> {
81 PartialEqAny::new(&self.0)
82 }
83 }
84
85 #[test]
86 fn test_cmp_any() {
87 let w1 = Wrap(1);
88 let w2 = Wrap(1);
89 let w3 = Wrap(2);
90
91 assert_eq!(w1.token() == w2.token(), true);
92 assert_eq!(w1.token() == w3.token(), false);
93
94 let w4 = Wrap("foo");
95 let w5 = Wrap("foo");
96 let w6 = Wrap("bar");
97
98 assert_eq!(w4.token() == w5.token(), true);
99 assert_eq!(w4.token() == w6.token(), false);
100
101 assert_eq!(w1.token() == w6.token(), false);
102 }
103
104 #[test]
105 #[allow(clippy::eq_op)]
106 fn always_false_cmp() {
107 let w = Wrap(1);
108 let f = PartialEqAny::always_false();
109
110 assert_eq!(f == f, false);
111 assert_eq!(f == w.token(), false);
112 }
113}