turbo_dyn_eq_hash/
lib.rs

1use std::{
2    any::{Any, TypeId},
3    hash::{Hash, Hasher},
4};
5
6/// A dynamic-dispatch version of the [`PartialEq`] trait. Implemented for every type that
7/// implements [`Any`] + [`PartialEq`].
8pub trait DynPartialEq: Any {
9    fn dyn_partial_eq(&self, other: &dyn Any) -> bool;
10}
11
12impl<T: Any + PartialEq> DynPartialEq for T {
13    fn dyn_partial_eq(&self, other: &dyn Any) -> bool {
14        other
15            .downcast_ref::<Self>()
16            .map(|other| PartialEq::eq(self, other))
17            .unwrap_or(false)
18    }
19}
20
21#[macro_export]
22macro_rules! impl_partial_eq_for_dyn {
23    ($ty:ty) => {
24        impl ::std::cmp::PartialEq for $ty {
25            fn eq(&self, other: &Self) -> bool {
26                $crate::DynPartialEq::dyn_partial_eq(self, other as &dyn ::std::any::Any)
27            }
28        }
29    };
30}
31
32/// A dynamic-dispatch version of the [`Eq`] trait. Implemented for every type that implements
33/// [`Any`] + [`Eq`].
34pub trait DynEq: DynPartialEq {}
35
36impl<T: Any + Eq> DynEq for T {}
37
38#[macro_export]
39macro_rules! impl_eq_for_dyn {
40    ($ty:ty) => {
41        impl ::std::cmp::Eq for $ty {}
42    };
43}
44
45/// A dynamic-dispatch version of the [`Hash`] trait. Implemented for every type that implements
46/// [`Any`] + [`Hash`].
47///
48/// The `TypeId::of::<Self>()` value is included in the resulting hash, so the hash generated by
49/// `DynEqHash` will not match the hash generated by the underlying `Hash` implementation. In other
50/// words, the hash of `T` will not match the hash of `T as dyn SomeDynHashTrait`.
51pub trait DynHash {
52    fn dyn_hash(&self, state: &mut dyn Hasher);
53}
54
55impl<T: Any + Hash> DynHash for T {
56    fn dyn_hash(&self, mut state: &mut dyn Hasher) {
57        Hash::hash(&(TypeId::of::<Self>(), self), &mut state);
58    }
59}
60
61#[macro_export]
62macro_rules! impl_hash_for_dyn {
63    ($ty:ty) => {
64        impl ::std::hash::Hash for $ty {
65            fn hash<H: ::std::hash::Hasher>(&self, state: &mut H) {
66                $crate::DynHash::dyn_hash(self, state as &mut dyn (::std::hash::Hasher))
67            }
68        }
69    };
70}