#![feature(const_type_id)]
#![feature(specialization)]
#![deny(
missing_docs, missing_debug_implementations, missing_copy_implementations, trivial_casts,
trivial_numeric_casts, unsafe_code, unused_import_braces, unused_qualifications
)]
use std::any;
use std::fmt;
pub type TypeId = any::TypeId;
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
pub enum FieldId<'a> {
Unnamed(usize),
Named(&'a str),
}
pub trait TypeInfo: DynamicTypeInfo {
const TYPE: Type;
fn field<A>(&self, _id: FieldId) -> Option<&A>
where
A: any::Any,
{
None
}
fn field_mut<A>(&mut self, _id: FieldId) -> Option<&mut A>
where
A: any::Any,
{
None
}
}
pub trait DynamicTypeInfo {
fn type_ref(&self) -> &'static Type;
fn variant(&self) -> Option<&str> {
None
}
fn field_any(&self, _id: FieldId) -> Option<&any::Any> {
None
}
fn field_any_mut(&mut self, _id: FieldId) -> Option<&mut any::Any> {
None
}
}
pub trait TryTypeInfo {
const TRY_TYPE: Option<&'static Type>;
}
impl<T> TryTypeInfo for T {
default const TRY_TYPE: Option<&'static Type> = None;
}
impl<T> TryTypeInfo for T
where
T: TypeInfo,
{
const TRY_TYPE: Option<&'static Type> = Some(&T::TYPE);
}
#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct Type {
pub id: TypeId,
pub module: &'static str,
pub ident: &'static str,
pub data: Data,
}
#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub enum Data {
Primitive,
Struct(DataStruct),
Enum(DataEnum),
Union(DataUnion),
}
#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct DataStruct {
pub fields: Fields,
}
#[allow(missing_copy_implementations)]
#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct DataEnum {
pub variants: &'static [Variant],
}
#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct DataUnion {
pub fields: FieldsNamed,
}
#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct Variant {
pub ident: &'static str,
pub fields: Fields,
}
#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub enum Fields {
Named(FieldsNamed),
Unnamed(FieldsUnnamed),
Unit,
}
#[allow(missing_copy_implementations)]
#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct FieldsNamed {
pub named: &'static [Field],
}
#[allow(missing_copy_implementations)]
#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct FieldsUnnamed {
pub unnamed: &'static [Field],
}
#[allow(missing_copy_implementations)]
#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct Field {
pub id: FieldId<'static>,
pub ident: Option<&'static str>,
pub ty: Option<&'static Type>,
}
impl Type {
pub fn fields(&self) -> &'static [Field] {
match self.data {
Data::Struct(DataStruct { ref fields, .. }) => fields.fields(),
_ => &[],
}
}
pub fn variants(&self) -> &'static [Variant] {
match self.data {
Data::Enum(DataEnum { ref variants, .. }) => variants,
_ => &[],
}
}
}
impl Fields {
pub fn fields(&self) -> &'static [Field] {
match *self {
Fields::Unit => &[],
Fields::Named(FieldsNamed { named, .. }) => named,
Fields::Unnamed(FieldsUnnamed { unnamed, .. }) => unnamed,
}
}
}
impl<'a> fmt::Display for FieldId<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
FieldId::Unnamed(idx) => idx.fmt(f),
FieldId::Named(name) => name.fmt(f),
}
}
}
macro_rules! impl_primitive {
($t:ty) => {
impl TypeInfo for $t {
const TYPE: Type = Type {
id: TypeId::of::<$t>(),
module: "",
ident: stringify!($t),
data: Data::Primitive,
};
}
impl DynamicTypeInfo for $t {
fn type_ref(&self) -> &'static Type {
&<Self as TypeInfo>::TYPE
}
}
};
}
impl_primitive!(u8);
impl_primitive!(u16);
impl_primitive!(u32);
impl_primitive!(u64);
impl_primitive!(usize);
impl_primitive!(i8);
impl_primitive!(i16);
impl_primitive!(i32);
impl_primitive!(i64);
impl_primitive!(isize);
impl_primitive!(f32);
impl_primitive!(f64);
impl_primitive!(bool);
impl_primitive!(char);