use sealed::sealed;
use crate::types::{IScriptable, Ref};
pub unsafe trait ScriptClass: Sized {
type Kind: ClassKind<Self>;
const NAME: &'static str;
}
#[sealed]
pub trait ClassKind<T> {
type NativeType;
fn fields(inst: &Self::NativeType) -> &T;
fn fields_mut(inst: &mut Self::NativeType) -> &mut T;
}
pub mod class_kind {
use super::*;
#[derive(Debug)]
pub struct Scripted;
#[sealed]
impl<T> ClassKind<T> for Scripted {
type NativeType = IScriptable;
#[inline]
fn fields(inst: &Self::NativeType) -> &T {
unsafe { &*inst.fields().as_ptr().cast::<T>() }
}
#[inline]
fn fields_mut(inst: &mut Self::NativeType) -> &mut T {
unsafe { &mut *inst.fields().as_ptr().cast::<T>() }
}
}
#[derive(Debug)]
pub struct Native;
#[sealed]
impl<T> ClassKind<T> for Native {
type NativeType = T;
#[inline]
fn fields(inst: &Self::NativeType) -> &T {
inst
}
#[inline]
fn fields_mut(inst: &mut Self::NativeType) -> &mut T {
inst
}
}
}
#[sealed]
pub trait ScriptClassOps: ScriptClass {
fn new_ref() -> Option<Ref<Self>>;
fn new_ref_with(init: impl FnOnce(&mut Self)) -> Option<Ref<Self>>;
}
#[sealed]
impl<T: ScriptClass> ScriptClassOps for T {
#[inline]
fn new_ref() -> Option<Ref<Self>> {
Ref::new()
}
#[inline]
fn new_ref_with(init: impl FnOnce(&mut Self)) -> Option<Ref<Self>> {
Ref::new_with(init)
}
}
pub type NativeType<T> = <<T as ScriptClass>::Kind as ClassKind<T>>::NativeType;