use std::{
cell::{Cell, RefCell, UnsafeCell},
ops::Deref,
rc::Rc,
sync::Arc,
};
pub auto trait Immutable {}
impl<T> !Immutable for UnsafeCell<T> {}
impl<T: Immutable> Immutable for Rc<T> {}
impl<T: Immutable> Immutable for Arc<T> {}
pub unsafe trait CheapEq {
const CHEAP_TO_EQ: bool;
fn cheap_eq(&self, other: &Self) -> bool;
}
unsafe impl<T: ?Sized> CheapEq for T {
default const CHEAP_TO_EQ: bool = false;
default fn cheap_eq(&self, _: &Self) -> bool {
false
}
}
unsafe impl<T: CheapEq + ?Sized> CheapEq for &T {
default const CHEAP_TO_EQ: bool = T::CHEAP_TO_EQ;
default fn cheap_eq(&self, other: &Self) -> bool {
if *self as *const _ == *other as *const _ {
T::cheap_eq(self.deref(), other.deref()) } else {
false
}
}
}
unsafe impl<T: CheapEq + ?Sized> CheapEq for &mut T {
default const CHEAP_TO_EQ: bool = T::CHEAP_TO_EQ;
default fn cheap_eq(&self, other: &Self) -> bool {
if *self as *const _ == *other as *const _ {
T::cheap_eq(self.deref(), other.deref()) } else {
false
}
}
}
unsafe impl<T: CheapEq + ?Sized> CheapEq for Box<T> {
default const CHEAP_TO_EQ: bool = T::CHEAP_TO_EQ;
default fn cheap_eq(&self, other: &Self) -> bool {
T::cheap_eq(self.deref(), other.deref()) }
}
unsafe impl<T: CheapEq + ?Sized> CheapEq for Rc<T> {
default const CHEAP_TO_EQ: bool = T::CHEAP_TO_EQ;
default fn cheap_eq(&self, other: &Self) -> bool {
T::cheap_eq(self.deref(), other.deref()) }
}
unsafe impl<T: CheapEq + ?Sized> CheapEq for Arc<T> {
default const CHEAP_TO_EQ: bool = T::CHEAP_TO_EQ;
default fn cheap_eq(&self, other: &Self) -> bool {
T::cheap_eq(self.deref(), other.deref()) }
}
unsafe impl<T: CheapEq + Copy + ?Sized> CheapEq for Cell<T> {
const CHEAP_TO_EQ: bool = T::CHEAP_TO_EQ;
fn cheap_eq(&self, other: &Self) -> bool {
T::cheap_eq(&self.get(), &other.get())
}
}
unsafe impl<T: CheapEq + ?Sized> CheapEq for RefCell<T> {
const CHEAP_TO_EQ: bool = T::CHEAP_TO_EQ;
fn cheap_eq(&self, other: &Self) -> bool {
T::cheap_eq(self.borrow().deref(), other.borrow().deref()) }
}
unsafe impl<T: Immutable + CheapEq + ?Sized> CheapEq for &T {
default const CHEAP_TO_EQ: bool = true;
default fn cheap_eq(&self, other: &Self) -> bool {
*self as *const _ == *other as *const _
}
}
unsafe impl<T: Immutable + CheapEq + ?Sized> CheapEq for Rc<T> {
const CHEAP_TO_EQ: bool = true;
fn cheap_eq(&self, other: &Self) -> bool {
Rc::as_ptr(self) == Rc::as_ptr(other)
}
}
unsafe impl<T: Immutable + CheapEq + ?Sized> CheapEq for Arc<T> {
const CHEAP_TO_EQ: bool = true;
fn cheap_eq(&self, other: &Self) -> bool {
Arc::as_ptr(self) == Arc::as_ptr(other)
}
}
unsafe impl CheapEq for str {
const CHEAP_TO_EQ: bool = true;
fn cheap_eq(&self, other: &Self) -> bool {
let c1 = self as *const _ == other as *const _;
let c2 = (*self).len() == (*other).len();
c1 && c2
}
}
unsafe impl<T: Immutable> CheapEq for [T] {
const CHEAP_TO_EQ: bool = true;
fn cheap_eq(&self, other: &Self) -> bool {
let c1 = self as *const _ == other as *const _;
let c2 = (*self).len() == (*other).len();
c1 && c2
}
}
macro_rules! impl_cheap_eq_for_primitives {
($($t:tt)*) => ($(
unsafe impl CheapEq for $t {
const CHEAP_TO_EQ: bool = true;
fn cheap_eq(&self, other: &Self) -> bool {
self == other
}
}
)*)
}
impl_cheap_eq_for_primitives! {
u8 u16 u32 u64 u128 usize
i8 i16 i32 i64 i128 isize
f32 f64 char bool ()
}