use core::{
any::{type_name, TypeId},
marker::PhantomData,
mem, ptr,
};
#[inline(always)]
pub(crate) fn type_eq<T: 'static, U: 'static>() -> bool {
mem::size_of::<T>() == mem::size_of::<U>()
&& mem::align_of::<T>() == mem::align_of::<U>()
&& mem::needs_drop::<T>() == mem::needs_drop::<U>()
&& TypeId::of::<T>() == TypeId::of::<U>()
&& type_name::<T>() == type_name::<U>()
}
#[inline(always)]
pub(crate) fn type_eq_non_static<T: ?Sized, U: ?Sized>() -> bool {
non_static_type_id::<T>() == non_static_type_id::<U>()
}
fn non_static_type_id<T: ?Sized>() -> TypeId {
trait NonStaticAny {
fn get_type_id(&self) -> TypeId
where
Self: 'static;
}
impl<T: ?Sized> NonStaticAny for PhantomData<T> {
fn get_type_id(&self) -> TypeId
where
Self: 'static,
{
TypeId::of::<T>()
}
}
let phantom_data = PhantomData::<T>;
NonStaticAny::get_type_id(unsafe {
mem::transmute::<&dyn NonStaticAny, &(dyn NonStaticAny + 'static)>(&phantom_data)
})
}
#[inline(always)]
pub(crate) unsafe fn transmute_unchecked<T, U>(value: T) -> U {
assert!(
mem::size_of::<T>() == mem::size_of::<U>(),
"cannot transmute_unchecked if Dst and Src have different size"
);
let dest = ptr::read(&value as *const T as *const U);
mem::forget(value);
dest
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn non_static_type_comparisons() {
assert!(type_eq_non_static::<u8, u8>());
assert!(type_eq_non_static::<&'static u8, &'static u8>());
assert!(type_eq_non_static::<&u8, &'static u8>());
assert!(!type_eq_non_static::<u8, i8>());
assert!(!type_eq_non_static::<u8, &'static u8>());
}
}