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,
}
}
}