use std::any::{type_name, TypeId};
use std::fmt::{Debug, Display};
use std::marker::PhantomData;
use crate::prelude::*;
#[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct CastError<T: Enumeration>(PhantomData<T>);
impl<T: Enumeration> Display for CastError<T> {
#[inline(always)]
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"Unable to cast to enumeration type {}",
type_name::<T>()
)
}
}
impl<T: Enumeration> std::error::Error for CastError<T> {}
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct Variant<T: Debug> {
type_id: TypeId,
index: T,
}
impl<T: Enumeration> From<T> for Variant<T::Index> {
#[inline(always)]
fn from(e: T) -> Self {
Self {
type_id: TypeId::of::<T>(),
index: e.to_index(),
}
}
}
impl<T: Debug> Variant<T> {
#[inline(always)]
pub fn new<E: Enumeration>(e: E) -> Variant<E::Index> {
Variant::from(e)
}
#[inline(always)]
pub fn type_id(self) -> TypeId {
self.type_id
}
#[inline(always)]
pub fn index(self) -> T {
self.index
}
#[inline(always)]
pub fn cast<E: Enumeration<Index = T>>(self) -> Result<E, CastError<E>> {
if TypeId::of::<E>() == self.type_id {
Ok(E::variant(self.index).unwrap())
}
else {
Err(CastError(PhantomData))
}
}
}
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct VariantWith<T: Debug, U: 'static> {
type_id: TypeId,
index: T,
value: &'static U,
}
impl<T: Enumeration> From<T> for VariantWith<T::Index, T::AssociatedValueType> {
#[inline(always)]
fn from(e: T) -> Self {
Self {
type_id: TypeId::of::<T>(),
index: e.to_index(),
value: e.value(),
}
}
}
impl<T: Debug, U: 'static> VariantWith<T, U> {
#[inline(always)]
pub fn new<E: Enumeration>(e: E) -> VariantWith<E::Index, E::AssociatedValueType> {
VariantWith::from(e)
}
#[inline(always)]
pub fn type_id(self) -> TypeId {
self.type_id
}
#[inline(always)]
pub fn index(self) -> T {
self.index
}
#[inline(always)]
pub fn value(self) -> &'static U {
self.value
}
#[inline(always)]
pub fn cast<E: Enumeration<Index = T, AssociatedValueType = U>>(
self,
) -> Result<E, CastError<E>> {
if TypeId::of::<E>() == self.type_id {
Ok(E::variant(self.index).unwrap())
}
else {
Err(CastError(PhantomData))
}
}
}