use std::fmt::Debug;
use std::hash::{Hash, Hasher};
use std::ops::Deref;
use std::sync::Arc;
pub fn arc_ptr_eq<T: ?Sized>(a: &Arc<T>, b: &Arc<T>) -> bool {
std::ptr::eq(Arc::as_ptr(a), Arc::as_ptr(b))
}
pub fn arc_ptr_hash<T: ?Sized>(a: &Arc<T>, hasher: &mut impl Hasher) {
std::ptr::hash(Arc::as_ptr(a), hasher)
}
#[derive(Clone)]
#[allow(private_bounds)] pub struct PtrEq<Ptr: PointerType>(Ptr);
impl<T> PartialEq for PtrEq<Arc<T>>
where
T: ?Sized,
{
fn eq(&self, other: &Self) -> bool {
arc_ptr_eq(&self.0, &other.0)
}
}
impl<T> Eq for PtrEq<Arc<T>> where T: ?Sized {}
impl<T> Hash for PtrEq<Arc<T>>
where
T: ?Sized,
{
fn hash<H: Hasher>(&self, state: &mut H) {
arc_ptr_hash(&self.0, state);
}
}
impl<Ptr> From<Ptr> for PtrEq<Ptr>
where
Ptr: PointerType,
{
fn from(ptr: Ptr) -> Self {
PtrEq(ptr)
}
}
impl<T> From<PtrEq<Arc<T>>> for Arc<T>
where
T: ?Sized,
{
fn from(wrapper: PtrEq<Arc<T>>) -> Self {
wrapper.0
}
}
impl<Ptr> Debug for PtrEq<Ptr>
where
Ptr: PointerType + Debug,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.0.fmt(f)
}
}
impl<Ptr> Deref for PtrEq<Ptr>
where
Ptr: PointerType,
{
type Target = Ptr;
fn deref(&self) -> &Self::Target {
&self.0
}
}
trait PointerType {}
impl<T> PointerType for Arc<T> where T: ?Sized {}
#[cfg(test)]
mod tests {
use super::*;
use std::hash::DefaultHasher;
#[test]
pub fn test_ptr_eq_wrapper() {
let a = Arc::new("Hello".to_string());
let b = Arc::new(a.deref().clone());
let c = Arc::new("world".to_string());
let wrapper = PtrEq(Arc::clone(&a));
assert_eq!(wrapper, wrapper);
assert_eq!(PtrEq(Arc::clone(&a)), PtrEq(Arc::clone(&a)));
assert_eq!(hash(PtrEq(Arc::clone(&a))), hash(PtrEq(Arc::clone(&a))));
assert_ne!(PtrEq(Arc::clone(&a)), PtrEq(Arc::clone(&b)));
assert_ne!(PtrEq(Arc::clone(&a)), PtrEq(Arc::clone(&c)));
}
fn hash<T: Hash>(value: T) -> u64 {
let hasher = &mut DefaultHasher::new();
value.hash(hasher);
hasher.finish()
}
}