flect 0.1.1

Rust reflection [WIP]
Documentation
use core::alloc::Layout;
use core::any::{self, TypeId};
use core::{mem, panic};

use crate::model::Model;
use crate::Reflect;

#[derive(Debug, Clone, Copy)]
pub struct ConstTypeId(fn () -> TypeId);

impl ConstTypeId {
    #[inline]
    pub const fn new<T: ?Sized + 'static>() -> Self {
        Self(|| TypeId::of::<T>())
    }

    #[inline]
    pub fn get(&self) -> any::TypeId {
        (self.0)()
    }
}

#[derive(Debug)]
pub struct Field<'ty> {
    pub name: &'ty str,
    pub model: &'ty Model<'ty>,
    pub offset: usize,
}

impl<'ty> Field<'ty> {
    pub const fn new<T: ?Sized + Reflect>(name: &'ty str, offset: usize) -> Self {
        Self { name, model: T::MODEL, offset }
    }
}

#[derive(Debug)]
pub struct StructType<'ty> {
    pub fields: &'ty [Field<'ty>],
}

#[derive(Debug)]
pub enum PrimitiveType {
    Bool,
    Char,
    U8,
    U16,
    U32,
    U64,
    U128,
    I8,
    I16,
    I32,
    I64,
    I128,
    F32,
    F64,
}

#[derive(Debug)]
pub enum TypeKind<'ty> {
    Primitive(PrimitiveType),
    Str,
    Struct(StructType<'ty>),
    Slice(&'ty Type<'ty>),
    Array {
        of: &'ty Type<'ty>,
        len: usize,
    },
    Ref {
        to: &'ty Model<'ty>,
        wide: bool,
    },
    Ptr {
        is_const: bool,
        to: &'ty Model<'ty>,
        wide: bool,
    },
}

#[derive(Debug,Clone,Copy)]
pub enum LayoutKind {
    Sized(Layout),
    Unsized,
}

impl LayoutKind {
    pub const fn as_sized(&self) -> Option<Layout> {
        match self {
            LayoutKind::Sized(layout) => Some(*layout),
            LayoutKind::Unsized => None,
        }
    }
}

#[derive(Debug)]
pub struct Type<'ty> {
    pub kind: TypeKind<'ty>,
    pub layout: LayoutKind,
    pub id: ConstTypeId,
}

impl<'ty> Type<'ty> {

    pub const fn ptr<T: Reflect + ?Sized + 'static>()  -> Self {
        let wide = mem::size_of::<*const T>() == mem::size_of::<*const [u8]>();
        let kind = TypeKind::Ptr { is_const: true, to: T::MODEL, wide };

        TypeBuilder::new::<*const T>().kind(kind).build()
    }

    pub const fn ptr_mut<T: Reflect + ?Sized + 'static>()  -> Self {
        let wide = mem::size_of::<*mut T>() == mem::size_of::<*mut [u8]>();
        let kind = TypeKind::Ptr { is_const: false, to: T::MODEL, wide };

        TypeBuilder::new::<*mut T>().kind(kind).build()
    }

    pub const fn reference<T: ?Sized + Reflect + 'static>()  -> Self {
        let wide = mem::size_of::<&T>() == mem::size_of::<&[u8]>();
        let kind = TypeKind::Ref { to: T::MODEL, wide };

        TypeBuilder::new::<&T>().kind(kind).build()
    }

    pub const fn primitive<T: 'static>(primitive: PrimitiveType) -> Self {
        TypeBuilder::new::<T>()
            .kind(TypeKind::Primitive(primitive))
            .build()
    }

    pub const fn array<T: Reflect + 'static, const N: usize>() -> Self {
        let layout = match Layout::array::<T>(N) {
            Ok(l) => l,
            Err(_) => panic!()
        };
        Self {
            kind: TypeKind::Array {
                of: T::MODEL.ty,
                len: N,
            },
            layout: LayoutKind::Sized(layout),
            id: ConstTypeId::new::<[T; N]>(),
        }
    }

    pub const fn slice<T: Reflect + 'static>() -> Self {
        Self {
            kind: TypeKind::Slice(T::MODEL.ty),
            layout: LayoutKind::Unsized,
            id: ConstTypeId::new::<[T]>(),
        }
    }

}

#[macro_export]
macro_rules! struct_type {
    ($( $n:path : $t:ty ),* $(,)?) => {
        &const { $crate::types::TypeBuilder::new::<Self>()
            .set_struct(&const {[
                $(
                    $crate::types::Field::new::<$t>(stringify!($n), offset_of!(Self, $n)),
                )*
            ]})
            .build()
        }
    };
}

pub struct TypeBuilder<'ty> {
    kind: Option<TypeKind<'ty>>,
    layout: LayoutKind,
    id: ConstTypeId,
}

impl<'ty> TypeBuilder<'ty> {

    pub const fn new<T: 'static>() -> Self {
        Self { kind: None, layout: LayoutKind::Sized(Layout::new::<T>()), id: ConstTypeId::new::<T>() }
    }

    pub const fn new_unsized<T: ?Sized + 'static>() -> Self {
        Self { kind: None, layout: LayoutKind::Unsized, id: ConstTypeId::new::<T>() }
    }

    pub const fn kind(&mut self, kind: TypeKind<'ty>) -> &mut Self {
        self.kind = Some(kind);
        self
    }

    pub const fn set_struct(&mut self, fields: &'ty [Field<'ty>]) -> &mut Self {
        self.kind = Some(TypeKind::Struct(StructType { fields }));
        self
    }

    pub const fn build(&mut self) -> Type<'ty> {
        Type { kind: self.kind.take().unwrap(), layout: self.layout, id: self.id }
    }
}