1use core::{
75 any::Any,
76 hash::{Hash, Hasher},
77 ops::Deref,
78};
79
80mod obj;
81
82pub use obj::Obj;
83
84pub trait AsAny: Any {
86 fn as_any(&self) -> &dyn Any;
87}
88
89impl<T: Any> AsAny for T {
90 fn as_any(&self) -> &(dyn Any) {
91 self as &dyn Any
92 }
93}
94
95pub trait EqObj: PartialEqObj {
97 fn as_eq_object(&self) -> &dyn EqObj;
98 fn to_eq_object(self) -> Box<dyn EqObj>;
99}
100
101impl<T> EqObj for T
102where
103 T: Eq + PartialEqObj,
104{
105 fn as_eq_object(&self) -> &dyn EqObj {
106 self
107 }
108
109 fn to_eq_object(self) -> Box<dyn EqObj> {
110 Box::new(self)
111 }
112}
113
114impl_eq! {
115 Obj<T> where <T: Deref<Target=X>, X: EqObj + ?Sized>,
116 dyn EqObj,
117}
118
119#[macro_export]
120macro_rules! impl_eq {
121 ($(
122 $Type:ty $(where <$(
123 $G:ident$(:
124 $($Gb:ident $(<$($GbIn:ident$(=$GbInEq:ty)?)+>)?)?
125 $(?$Gbq:ident)?
126 $(
127 +
128 $($Gb2:ident $(<$($GbIn2:ident$(=$GbInEq2:ty)?)+>)?)?
129 $(?$Gbq2:ident)?
130 )*
131 )?
132 ),+>)?
133 ),*$(,)?) => {$(
134 impl$(<$(
135 $G$(:
136 $($Gb $(<$($GbIn$(=$GbInEq)?)+>)?)?
137 $(?$Gbq)?
138 $(
139 +
140 $($Gb2 $({$($GbIn2$(=$GbInEq2:ty)?)+})?)?
141 $(?$Gbq2)?
142 )*
143 )?
144 ),+>)?
145 Eq for $Type where $Type: 'static {})*
146 };
147}
148
149pub trait PartialEqObj: AsAny {
151 fn eq_object(&self, other: &dyn PartialEqObj) -> bool;
152 fn as_partial_eq_object(&self) -> &dyn PartialEqObj;
153 fn to_partial_eq_object(self) -> Box<dyn PartialEqObj>;
154}
155
156impl<T> PartialEqObj for T
157where
158 T: PartialEq + AsAny,
159{
160 fn eq_object(&self, other: &dyn PartialEqObj) -> bool {
161 match other.as_any().downcast_ref::<Self>() {
162 Some(other) => self == other,
163 None => false,
164 }
165 }
166
167 fn as_partial_eq_object(&self) -> &dyn PartialEqObj {
168 self
169 }
170
171 fn to_partial_eq_object(self) -> Box<dyn PartialEqObj> {
172 Box::new(self)
173 }
174}
175
176impl_partial_eq! {
177 Obj<T> where <T: Deref<Target=X>, X: PartialEqObj + ?Sized>,
178 dyn PartialEqObj,
179 dyn EqObj,
180}
181
182#[macro_export]
183macro_rules! impl_partial_eq {
184 ($(
185 $Type:ty $(where <$(
186 $G:ident$(:
187 $($Gb:ident $(<$($GbIn:ident$(=$GbInEq:ty)?)+>)?)?
188 $(?$Gbq:ident)?
189 $(
190 +
191 $($Gb2:ident $(<$($GbIn2:ident$(=$GbInEq2:ty)?)+>)?)?
192 $(?$Gbq2:ident)?
193 )*
194 )?
195 ),+>)?
196 ),*$(,)?) => {$(
197 impl$(<$(
198 $G$(:
199 $($Gb $(<$($GbIn$(=$GbInEq)?)+>)?)?
200 $(?$Gbq)?
201 $(
202 +
203 $($Gb2 $({$($GbIn2$(=$GbInEq2:ty)?)+})?)?
204 $(?$Gbq2)?
205 )*
206 )?
207 ),+>)?
208 PartialEq for $Type where $Type: 'static {
209 fn eq(&self, other: &Self) -> bool {
210 self.deref().eq_object(other.deref().as_partial_eq_object())
211 }
212 })*
213 };
214}
215
216pub trait HashObj {
218 fn hash_object(&self, state: &mut dyn Hasher);
219 fn as_hash_object(&self) -> &dyn HashObj;
220 fn to_hash_object(self) -> Box<dyn HashObj>
221 where
222 Self: 'static;
223}
224
225impl<T: Hash> HashObj for T {
226 fn hash_object(&self, mut state: &mut dyn Hasher) {
227 self.hash(&mut state);
228 }
229
230 fn as_hash_object(&self) -> &dyn HashObj {
231 self
232 }
233
234 fn to_hash_object(self) -> Box<dyn HashObj>
235 where
236 Self: 'static,
237 {
238 Box::new(self)
239 }
240}
241
242impl_hash! {
243 Obj<T> where <T: Deref<Target=X>, X: HashObj + ?Sized>,
244 dyn HashObj,
245}
246
247#[macro_export]
248macro_rules! impl_hash {
249 ($(
250 $Type:ty $(where <$(
251 $G:ident$(:
252 $($Gb:ident $(<$($GbIn:ident$(=$GbInEq:ty)?)+>)?)?
253 $(?$Gbq:ident)?
254 $(
255 +
256 $($Gb2:ident $(<$($GbIn2:ident$(=$GbInEq2:ty)?)+>)?)?
257 $(?$Gbq2:ident)?
258 )*
259 )?
260 ),+>)?
261 ),*$(,)?) => {$(
262 impl$(<$(
263 $G$(:
264 $($Gb $(<$($GbIn$(=$GbInEq)?)+>)?)?
265 $(?$Gbq)?
266 $(
267 +
268 $($Gb2 $({$($GbIn2$(=$GbInEq2:ty)?)+})?)?
269 $(?$Gbq2)?
270 )*
271 )?
272 ),+>)?
273 std::hash::Hash for $Type {
274 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
275 self.deref().hash_object(state);
276 }
277 }
278 )*};
279}
280
281#[cfg(test)]
282mod test {
283 use std::collections::hash_map::DefaultHasher;
284
285 use super::*;
286
287 #[test]
288 fn eq() {
289 let x: Box<dyn EqObj> = Box::new(10);
290 let y: Box<dyn EqObj> = Box::new(10);
291 let z: Box<dyn EqObj> = Box::new(11);
292 if x != y {
293 panic!("should be equal")
294 }
295 if x == z {
296 panic!("should not be equal")
297 }
298 }
299
300 #[test]
301 fn hash_works() {
302 let x: &str = "Hello, World!";
303 let y: &dyn HashObj = "Hello, World!".as_hash_object();
304 let z: &dyn HashObj = "banana".as_hash_object();
305 assert_eq!(hash(x), hash(y));
306 assert_ne!(hash(y), hash(z));
307 }
308
309 fn hash<T: Hash>(t: T) -> u64 {
310 let mut hasher = DefaultHasher::new();
311 t.hash(&mut hasher);
312 hasher.finish()
313 }
314
315 mod obj_tests {
316 use crate::*;
317 trait MyHash: HashObj {}
319 #[derive(Hash)]
320 struct MyHashWrapper(Obj<Box<dyn MyHash>>);
321 impl<T> MyHash for T where T: Hash {}
322
323 trait MyPartialEq: PartialEqObj {}
325 #[derive(PartialEq)]
326 struct MyPartialEqWrapper(Obj<Box<dyn MyPartialEq>>);
327 impl<T> MyPartialEq for T where T: PartialEq + 'static {}
328
329 trait MyEq: EqObj + PartialEqObj + std::fmt::Debug {}
331 #[derive(PartialEq, Eq, Debug)]
332 struct MyEqWrapper(Obj<Box<dyn MyEq>>);
333 impl<T> MyEq for T where T: Eq + 'static + std::fmt::Debug {}
334
335 #[test]
336 fn hash_obj_works() {
337 let a = super::hash(0);
338 let b = super::hash(Box::new(0));
339 let c = super::hash(Obj(Box::new(0)));
340 let d = super::hash(MyHashWrapper(Obj(Box::new(0))));
341 assert_eq!(a, b);
342 assert_eq!(a, c);
343 assert_eq!(a, d);
344 }
345
346 #[test]
347 fn obj_box_dyn_custom_eq() {
348 assert_eq!(
349 Obj(Box::new(0) as Box<dyn MyEq>),
350 Obj(Box::new(0) as Box<dyn MyEq>)
351 );
352 assert_ne!(
353 Obj(Box::new(0) as Box<dyn MyEq>),
354 Obj(Box::new(1) as Box<dyn MyEq>)
355 );
356 }
357
358 #[test]
359 fn wrapped_obj_box_dyn_custom_eq() {
360 assert_eq!(
361 MyEqWrapper(Obj(Box::new(0) as Box<dyn MyEq>)),
362 MyEqWrapper(Obj(Box::new(0) as Box<dyn MyEq>))
363 );
364 assert_ne!(
365 MyEqWrapper(Obj(Box::new(0) as Box<dyn MyEq>)),
366 MyEqWrapper(Obj(Box::new(1) as Box<dyn MyEq>))
367 );
368 }
369
370 #[test]
371 fn obj_box_eq() {
372 assert_eq!(Obj(Box::new(0)), Obj(Box::new(0)));
373 assert_ne!(Obj(Box::new(0)), Obj(Box::new(1)));
374 }
375
376 #[test]
377 fn wrapped_ob_box_eq() {
378 assert_eq!(MyEqWrapper(Obj(Box::new(0))), MyEqWrapper(Obj(Box::new(0))));
379 assert_ne!(MyEqWrapper(Obj(Box::new(0))), MyEqWrapper(Obj(Box::new(1))));
380 }
381 }
382
383 mod impl_tests {
384 use crate::*;
385 trait MyTrait: HashObj + EqObj + PartialEqObj {}
386 impl<T> MyTrait for T where T: Hash + Eq + PartialEq + 'static {}
387
388 impl_hash!(dyn MyTrait);
389 impl_eq!(dyn MyTrait);
390 impl_partial_eq!(dyn MyTrait);
391
392 #[test]
393 fn box_dyn_custom_eq() {
394 if Box::new(0) as Box<dyn MyTrait> != Box::new(0) as Box<dyn MyTrait> {
395 panic!("should be equal");
396 }
397 if Box::new(0) as Box<dyn MyTrait> == Box::new(1) as Box<dyn MyTrait> {
398 panic!("should not be equal");
399 }
400 }
401 }
402}
403
404