use crate::static_type_map::StaticTypeMap;
use crate::Guid;
use once_cell::sync::OnceCell;
use std::fmt;
#[repr(u8)]
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
pub enum TypeId<'a> {
Concrete(Guid),
Pointer(PointerTypeId<'a>),
Array(ArrayTypeId<'a>),
}
#[repr(C)]
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
pub struct PointerTypeId<'a> {
pub pointee: &'a TypeId<'a>,
pub mutable: bool,
}
#[repr(C)]
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
pub struct ArrayTypeId<'a> {
pub element: &'a TypeId<'a>,
}
unsafe impl<'a> Send for TypeId<'a> {}
unsafe impl<'a> Sync for TypeId<'a> {}
impl<'a> From<Guid> for TypeId<'a> {
fn from(guid: Guid) -> Self {
TypeId::Concrete(guid)
}
}
impl<'a> From<PointerTypeId<'a>> for TypeId<'a> {
fn from(pointer: PointerTypeId<'a>) -> Self {
TypeId::Pointer(pointer)
}
}
impl<'a> fmt::Display for TypeId<'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
TypeId::Concrete(guid) => guid.fmt(f),
TypeId::Pointer(pointer) => pointer.fmt(f),
TypeId::Array(array) => array.fmt(f),
}
}
}
impl<'a> fmt::Display for PointerTypeId<'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.mutable {
write!(f, "*mut ")
} else {
write!(f, "*const ")
}?;
self.pointee.fmt(f)
}
}
impl<'a> fmt::Display for ArrayTypeId<'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "[{}]", &self.element)
}
}
pub trait HasStaticTypeId {
fn type_id() -> &'static TypeId<'static>;
}
impl<T: HasStaticTypeId + 'static> HasStaticTypeId for *const T {
fn type_id() -> &'static TypeId<'static> {
static VALUE: OnceCell<StaticTypeMap<TypeId>> = OnceCell::new();
let map = VALUE.get_or_init(Default::default);
map.call_once::<T, _>(|| {
PointerTypeId {
pointee: T::type_id(),
mutable: false,
}
.into()
})
}
}
impl<T: HasStaticTypeId + 'static> HasStaticTypeId for *mut T {
fn type_id() -> &'static TypeId<'static> {
static VALUE: OnceCell<StaticTypeMap<TypeId>> = OnceCell::new();
let map = VALUE.get_or_init(Default::default);
map.call_once::<T, _>(|| {
PointerTypeId {
pointee: T::type_id(),
mutable: true,
}
.into()
})
}
}
#[cfg(test)]
mod test {
use crate::{ArrayTypeId, HasStaticTypeId, PointerTypeId, PrimitiveType, TypeId};
#[test]
fn display() {
assert_eq!(i32::type_id().to_string(), i32::guid().to_string());
assert_eq!(f64::type_id().to_string(), f64::guid().to_string());
assert_eq!(
std::ffi::c_void::type_id().to_string(),
std::ffi::c_void::guid().to_string()
);
let i32_type_id = i32::type_id();
assert_eq!(
TypeId::Pointer(PointerTypeId {
pointee: i32_type_id,
mutable: false
})
.to_string(),
format!("*const {}", i32::guid())
);
assert_eq!(
TypeId::Pointer(PointerTypeId {
pointee: i32_type_id,
mutable: true
})
.to_string(),
format!("*mut {}", i32::guid())
);
assert_eq!(
TypeId::Array(ArrayTypeId {
element: i32_type_id
})
.to_string(),
format!("[{}]", i32::guid())
);
}
}