flect 0.1.1

Rust reflection [WIP]
Documentation
use core::fmt::{self, Debug, Display};
use core::marker::PhantomData;

use crate::ptr::OpaqueConst;
use crate::types::Type;
use crate::Reflect;

#[derive(Debug)]
pub struct Model<'m> {
    pub ty: &'m Type<'m>,
    pub vtable: &'m VTable,
}

pub type DisplayFn = for<'a> unsafe fn (OpaqueConst<'a>, f: &mut fmt::Formatter<'_>) -> fmt::Result;

pub type DebugFn = DisplayFn;

#[derive(Debug)]
pub struct VTable {
    pub display: Option<DisplayFn>,
    pub debug: Option<DebugFn>,
}

pub struct VTableBuilder<T: ?Sized> {
    pub display: Option<DisplayFn>,
    pub debug: Option<DebugFn>,
    _m: PhantomData<T>,
}

impl<T: ?Sized> VTableBuilder<T> {
    pub const fn new() -> Self {
        Self { display: None, debug: None, _m: PhantomData }
    }

    pub const fn display(&mut self) -> &mut Self
    where
        T: Display
    {
        self.display = Some(|slf, f| {
            let r = unsafe { slf.cast::<T>().as_ref().unwrap() };
            <T as Display>::fmt(r, f)
        });
        self
    }

    pub const fn debug(&mut self) -> &mut Self
    where
        T: Debug
    {
        self.debug = Some(|slf, f| {
            let r = unsafe { slf.cast::<T>().as_ref().unwrap() };
            <T as Debug>::fmt(r, f)
        });
        self
    }

    pub const fn debug_slice<Of: Reflect>(&mut self) -> &mut Self {
        if Of::VTABLE.debug.is_some() {
            self.debug = Some(|slf, f| {
                let slice = unsafe { slf.cast_ref::<[Of]>() };
                write!(f, "[")?;
                for (i, elem) in slice.iter().enumerate() {
                    if i > 0 {
                        write!(f, ", ")?;
                    }
                    let dbg = Of::VTABLE.debug.unwrap();
                    let ptr = OpaqueConst::new(elem);
                    unsafe { dbg(ptr, f)? }
                }
                write!(f, "]")
            });
        }
        self
    }

    pub const fn debug_array<Of: Reflect, const N: usize>(&mut self) -> &mut Self {
        if Of::VTABLE.debug.is_some() {
            self.debug = Some(|slf, f| {
                let slice = unsafe { slf.cast_ref::<[Of; N]>() };
                write!(f, "[")?;
                for (i, elem) in slice.iter().enumerate() {
                    if i > 0 {
                        write!(f, ", ")?;
                    }
                    let dbg = Of::VTABLE.debug.unwrap();
                    let ptr = OpaqueConst::new(elem);
                    unsafe { dbg(ptr, f)? }
                }
                write!(f, "]")
            });
        }
        self
    }

    pub const fn build(&mut self) -> VTable {
        VTable { display: self.display, debug: self.debug }
    }
}

impl<T: ?Sized> Default for VTableBuilder<T> {
    fn default() -> Self {
        Self::new()
    }
}

pub struct ModelBuilder<'m> {
    ty: Option<&'m Type<'m>>,
    vtable: &'m VTable,
}

impl<'m> ModelBuilder<'m> {
    pub const fn new<T: ?Sized + Reflect>() -> Self {
        Self { ty: None, vtable: T::VTABLE }
    }

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

    pub const fn build(&mut self) -> Model<'m> {
       Model {
           ty: self.ty.unwrap(),
           vtable: self.vtable,
       }
    }
}