#![warn(missing_docs)]
use std::hash::{Hash, Hasher};
use std::mem::size_of_val;
use std::ops::Deref;
use std::ptr;
use std::rc::{Rc, Weak as WeakRc};
use std::sync::{Arc, Weak as WeakArc};
pub trait Id {
fn same(&self, other: &Self) -> bool;
fn hash<H: Hasher>(&self, state: &mut H);
}
impl<'a, T: ?Sized> Id for &'a T {
fn same(&self, other: &Self) -> bool {
(size_of_val(*self) == 0 && size_of_val(*other) == 0) || ptr::eq(*self, *other)
}
fn hash<H: Hasher>(&self, state: &mut H) {
if size_of_val(*self) != 0 {
Hash::hash(&ptr::addr_of!(*self), state)
}
}
}
impl<'a, T: ?Sized> Id for Rc<T> {
fn same(&self, other: &Self) -> bool {
Rc::ptr_eq(self, &other)
}
fn hash<H: Hasher>(&self, state: &mut H) {
Hash::hash(&Rc::as_ptr(self), state)
}
}
impl<'a, T: ?Sized> Id for WeakRc<T> {
fn same(&self, other: &Self) -> bool {
WeakRc::ptr_eq(self, &other)
}
fn hash<H: Hasher>(&self, state: &mut H) {
Hash::hash(&WeakRc::as_ptr(self), state)
}
}
impl<'a, T: ?Sized> Id for Arc<T> {
fn same(&self, other: &Self) -> bool {
Arc::ptr_eq(self, &other)
}
fn hash<H: Hasher>(&self, state: &mut H) {
Hash::hash(&Arc::as_ptr(self), state)
}
}
impl<'a, T: ?Sized> Id for WeakArc<T> {
fn same(&self, other: &Self) -> bool {
WeakArc::ptr_eq(self, &other)
}
fn hash<H: Hasher>(&self, state: &mut H) {
Hash::hash(&WeakArc::as_ptr(self), state)
}
}
#[derive(Clone, Copy, Debug)]
pub struct ById<T: ?Sized + Id>(
)
pub T,
);
impl<T: ?Sized + Id> PartialEq for ById<T> {
fn eq(&self, other: &Self) -> bool {
Id::same(&self.0, &other.0)
}
}
impl<T: ?Sized + Id> Eq for ById<T> {}
impl<T: ?Sized + Id> Hash for ById<T> {
fn hash<H: Hasher>(&self, state: &mut H) {
Id::hash(&self.0, state)
}
}
#[derive(Clone, Copy, Debug)]
pub struct ByIdDeref<T: ?Sized>(
)
pub T,
)
where
T: Deref,
<T as Deref>::Target: Id;
impl<T: ?Sized> PartialEq for ByIdDeref<T>
where
T: Deref,
<T as Deref>::Target: Id,
{
fn eq(&self, other: &Self) -> bool {
Id::same(&*self.0, &*other.0)
}
}
impl<T: ?Sized> Eq for ByIdDeref<T>
where
T: Deref,
<T as Deref>::Target: Id,
{
}
impl<T: ?Sized> Hash for ByIdDeref<T>
where
T: Deref,
<T as Deref>::Target: Id,
{
fn hash<H: Hasher>(&self, state: &mut H) {
Id::hash(&*self.0, state)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_two_refs_to_same_value() {
let v = 1;
let r1 = &v;
let r2 = &v;
assert_eq!(ById(r1), ById(r2));
}
#[test]
fn test_two_boxes() {
#[derive(Debug)]
struct S {
_value: i32,
}
let v1 = Box::new(S { _value: 1 });
let v2 = Box::new(S { _value: 2 });
let r1: &S = &v1;
let r2: &S = &v2;
assert_eq!(ById(r1), ById(r1));
assert_ne!(ById(r1), ById(r2));
}
#[test]
fn test_unit_type_naive() {
let v1 = ();
let v2 = ();
let r1: &() = &v1;
let r2: &() = &v2;
assert_eq!(ById(r1), ById(r2));
}
#[test]
fn test_unit_type_unique_via_rc() {
use std::rc::Rc;
let v1 = ();
let v2 = ();
let rc1 = Rc::new(v1);
let rc2 = Rc::new(v2);
let r1: &() = &*rc1;
let r2: &() = &*rc2;
assert_eq!(ById(r1), ById(r2));
}
#[test]
fn test_empty_slice() {
let v = vec![5, 6, 7];
let r1: &[i32] = &v[0..0];
let r2: &[i32] = &v[1..1];
assert_eq!(ById(r1), ById(r2));
}
#[test]
fn test_nonempty_slices() {
let v1 = vec![5, 6, 7];
let v2 = vec![5, 6, 7];
let r1: &[i32] = &v1[0..1];
let r2: &[i32] = &v1[0..1];
let r3: &[i32] = &v1[0..2];
let r4: &[i32] = &v2[0..1];
assert_eq!(ById(r1), ById(r1));
assert_eq!(ById(r1), ById(r2));
assert_ne!(ById(r1), ById(r3));
assert_ne!(ById(r1), ById(r4));
}
#[test]
fn test_rc() {
use std::rc::Rc;
let v1 = vec![9];
let v2 = vec![9];
let r1 = Rc::new(v1);
let r2 = Rc::new(v2);
let r3 = r1.clone();
assert_ne!(ById(r1.clone()), ById(r2.clone()));
assert_eq!(ById(r1.clone()), ById(r3.clone()));
}
#[test]
fn test_arc_with_szt() {
use std::sync::Arc;
let r1 = Arc::new(());
let r2 = Arc::new(());
let r3 = r1.clone();
assert_ne!(ById(r1.clone()), ById(r2.clone()));
assert_eq!(ById(r1.clone()), ById(r3.clone()));
}
#[test]
fn test_hash_set() {
use std::collections::HashSet;
fn count_distinct<T>(slice: &[&T]) -> usize {
let mut counted: HashSet<ById<&T>> = HashSet::new();
let mut count: usize = 0;
for item in slice {
if counted.insert(ById(item)) {
count += 1;
}
}
count
}
let v1 = "X".to_string();
let v2 = "X".to_string();
let v3 = "X".to_string();
assert_eq!(count_distinct(&vec![&v1, &v2, &v1, &v3]), 3);
}
#[test]
fn test_by_id_deref() {
use std::rc::Rc;
let rc1 = Rc::new(());
let rc2 = Rc::new(());
let rc3 = rc1.clone();
assert_ne!(ById(&rc1.clone()), ById(&rc2.clone()));
assert_ne!(ById(&rc1.clone()), ById(&rc3.clone()));
assert_ne!(ByIdDeref(&rc1.clone()), ByIdDeref(&rc2.clone()));
assert_eq!(ByIdDeref(&rc1.clone()), ByIdDeref(&rc3.clone()));
}
}