#![cfg_attr(feature = "nightly", feature(core_intrinsics))]
use std::any::{Any, TypeId};
use std::fmt;
use std::hash;
use std::cmp;
use std::borrow::Cow;
#[derive(Clone, Copy, Eq, Ord, Debug)]
#[cfg(feature = "nightly")]
pub struct TypeDef {
id: TypeId,
name: &'static str,
}
#[derive(Clone, Copy, Eq, Ord, Debug)]
#[cfg(not(feature = "nightly"))]
pub struct TypeDef {
id: TypeId,
}
impl TypeDef {
#[cfg(feature = "nightly")]
pub fn of<T: Any>() -> TypeDef {
use std::intrinsics::type_name;
TypeDef {
id: TypeId::of::<T>(),
name: unsafe { type_name::<T>() },
}
}
#[cfg(not(feature = "nightly"))]
pub fn of<T: Any>() -> TypeDef {
TypeDef {
id: TypeId::of::<T>(),
}
}
pub fn id_of<T: Any>() -> TypeId {
TypeId::of::<T>()
}
#[cfg(feature = "nightly")]
pub fn name_of<T: Any>() -> Cow<'static, str> {
use std::intrinsics::type_name;
Cow::Borrowed(unsafe { type_name::<T>() })
}
#[cfg(not(feature = "nightly"))]
pub fn name_of<T: Any>() -> Cow<'static, str> {
Cow::Owned(format!("{}", unsafe { ::std::mem::transmute_copy::<TypeId, u64>(&TypeId::of::<T>()) }))
}
pub fn is<T: Any>(&self) -> bool {
self.id == TypeId::of::<T>()
}
#[cfg(feature = "nightly")]
pub fn get_str(&self) -> Cow<'static, str> {
Cow::Borrowed(self.name)
}
#[cfg(not(feature = "nightly"))]
pub fn get_str(&self) -> Cow<'static, str> {
Cow::Owned(format!("{}", unsafe { ::std::mem::transmute_copy::<TypeId, u64>(&self.id) }))
}
}
impl PartialOrd for TypeDef {
#[inline(always)]
fn partial_cmp(&self, other: &TypeDef) -> Option<cmp::Ordering> {
self.id.partial_cmp(&other.id)
}
}
impl hash::Hash for TypeDef {
#[inline(always)]
fn hash<H: hash::Hasher>(&self, state: &mut H) {
self.id.hash(state)
}
}
impl PartialEq for TypeDef {
#[inline(always)]
fn eq(&self, other: &TypeDef) -> bool {
self.id == other.id
}
}
impl fmt::Display for TypeDef {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", &self.get_str())
}
}
#[cfg(test)]
mod test {
use super::TypeDef;
#[test]
fn should_match_type() {
assert!(TypeDef::of::<i16>().is::<i16>());
}
#[test]
fn should_not_match_incorrect_type() {
assert!(!TypeDef::of::<i16>().is::<i32>());
}
#[test]
#[cfg(not(feature = "nightly"))]
fn should_return_type_name() {
assert_eq!(TypeDef::of::<i16>().get_str().into_owned(), format!("{:?}", type_id_fallback::<i16>()));
assert_eq!(TypeDef::of::<i64>().get_str().into_owned(), format!("{:?}", type_id_fallback::<i64>()));
}
#[test]
#[cfg(feature = "nightly")]
fn should_return_type_name() {
assert_eq!(&TypeDef::of::<i16>().get_str(), "i16");
assert_eq!(&TypeDef::of::<i64>().get_str(), "i64");
}
#[test]
fn should_be_equal_to_another_typedef_of_the_same_type() {
assert_eq!(TypeDef::of::<i16>(), TypeDef::of::<i16>());
}
#[test]
fn should_not_be_equal_to_another_typedef_of_different_type() {
assert!(TypeDef::of::<i16>() != TypeDef::of::<i32>());
}
#[cfg(not(feature = "nightly"))]
fn type_id_fallback<T: 'static>() -> u64 {
use std::any::TypeId;
unsafe { ::std::mem::transmute_copy::<TypeId, u64>(&TypeId::of::<T>()) }
}
}