use crate::{Any, Hash, Hasher, HasherFx, TypeId};
use core::any::type_name_of_val;
#[cfg(feature = "alloc")]
use crate::Box;
trait Sealed {}
impl<T: ?Sized + Any> Sealed for T {}
impl<T: ?Sized + Any> AnyExt for T {}
#[doc = crate::_tags!(code)]
#[doc = crate::_doc_location!("code")]
#[rustfmt::skip]
#[expect(private_bounds, reason = "Sealed")]
pub trait AnyExt: Any + Sealed {
#[must_use]
fn type_id() -> TypeId { TypeId::of::<Self>() }
#[must_use]
fn type_of(&self) -> TypeId { TypeId::of::<Self>() }
#[must_use]
fn type_name(&self) -> &'static str { type_name_of_val(self) }
#[must_use]
fn type_is<T: 'static>(&self) -> bool { self.type_id() == TypeId::of::<T>() }
fn type_hash(&self) -> u64 {
let hasher = HasherFx::<u64>::default();
self.type_hash_with(hasher)
}
fn type_hash_with<H: Hasher>(&self, mut hasher: H) -> u64 {
TypeId::of::<Self>().hash(&mut hasher);
hasher.finish()
}
#[must_use]
fn as_any_ref(&self) -> &dyn Any where Self: Sized { self }
#[must_use]
fn as_any_mut(&mut self) -> &mut dyn Any where Self: Sized { self }
#[must_use]
#[cfg(feature = "alloc")]
fn as_any_box(self: Box<Self>) -> Box<dyn Any> where Self: Sized { self }
#[must_use]
#[cfg(all(not(feature = "safe_code"), feature = "unsafe_layout"))]
#[cfg_attr(nightly_doc, doc(cfg(all(feature = "unsafe_layout", not(feature = "safe_code")))))]
fn downcast_ref<T: 'static>(&self) -> Option<&T> {
unsafe { (*self).type_is::<T>().then(|| &*<*const _>::cast(self)) }
}
#[must_use]
#[cfg(all(not(feature = "safe_code"), feature = "unsafe_layout"))]
#[cfg_attr(nightly_doc, doc(cfg(all(feature = "unsafe_layout", not(feature = "safe_code")))))]
fn downcast_mut<T: 'static>(&mut self) -> Option<&mut T> {
unsafe { (*self).type_is::<T>().then(|| &mut *<*mut _>::cast(self)) }
}
}
#[cfg(test)]
mod tests {
use crate::AnyExt;
#[test]
fn closure_type_ids() {
let closure1 = || {};
let closure2 = || {};
let closure_with_env = |x: i32| x + 1;
assert_ne!(closure1.type_of(), closure2.type_of());
assert_ne!(closure1.type_of(), closure_with_env.type_of());
assert_ne!(closure2.type_of(), closure_with_env.type_of());
assert_eq!(closure1.type_name(), closure2.type_name());
assert_eq!(closure1.type_name(), closure_with_env.type_name());
}
}