Skip to content

Commit

Permalink
improve SQHandle
Browse files Browse the repository at this point in the history
  • Loading branch information
catornot committed Aug 31, 2024
1 parent d1cfbc4 commit 49e6381
Show file tree
Hide file tree
Showing 2 changed files with 109 additions and 47 deletions.
38 changes: 24 additions & 14 deletions src/high/squirrel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,16 +133,16 @@ impl CSquirrelVMHandle {
}

/// runtime check for [`SQObject`] types
pub struct SQHandle<H: IsSQObject> {
pub struct SQHandle<'a, H: IsSQObject<'a>> {
inner: SQObject,
marker: PhantomData<H>,
marker: PhantomData<&'a H>,
}

impl<H: IsSQObject> SQHandle<H> {
impl<'a, H: IsSQObject<'a>> SQHandle<'a, H> {
/// creates a new [`SQHandle`] by checking if the sqobject has the correct type at runtime
pub fn try_new(value: SQObject) -> Result<Self, SQObject> {
let ty = value._Type;
if ty == H::OT_TYPE || ty == H::RT_TYPE {
if ty == H::OT_TYPE {
Ok(Self {
inner: value,
marker: PhantomData,
Expand All @@ -164,41 +164,51 @@ impl<H: IsSQObject> SQHandle<H> {
}

/// a getter
pub const fn get(&self) -> &SQObject {
pub const fn get_obj(&self) -> &SQObject {
&self.inner
}

/// a mut getter
pub fn get_mut(&mut self) -> &mut SQObject {
pub fn get_mut_obj(&mut self) -> &mut SQObject {
&mut self.inner
}

/// consumes itself and returns the [`SQObject`]
pub const fn take(self) -> SQObject {
pub const fn take_obj(self) -> SQObject {
self.inner
}

/// a getter
pub fn get(&'a self) -> &H {
H::extract(&self.inner._VAL)
}

/// a mut getter
pub fn get_mut(&'a mut self) -> &mut H {
H::extract_mut(&mut self.inner._VAL)
}
}

impl SQHandle<SQClosure> {
impl<'a> SQHandle<'a, SQClosure> {
/// used in some macros to enforce type safety
pub fn as_callable(&mut self) -> *mut SQObject {
&mut self.inner as *mut SQObject
}
}

/// provides invariance for calling squirrel functions with little overhead
pub struct SquirrelFn<T: IntoSquirrelArgs> {
pub(crate) func: SQHandle<SQClosure>,
pub struct SquirrelFn<'a, T: IntoSquirrelArgs> {
pub(crate) func: SQHandle<'a, SQClosure>,
pub(crate) phantom: PhantomData<*mut T>,
}

impl<T: IntoSquirrelArgs> SquirrelFn<T> {
impl<'a, T: IntoSquirrelArgs> SquirrelFn<'a, T> {
/// creates a new [`SquirrelFn`] using the invariance of [`SQHandle<SQClosure>`]
///
/// # Safety
///
/// doesn't check if the function passed has the correct args and return type
pub const unsafe fn new_unchecked(obj: SQHandle<SQClosure>) -> Self {
pub const unsafe fn new_unchecked(obj: SQHandle<'a, SQClosure>) -> Self {
Self {
func: obj,
phantom: PhantomData,
Expand Down Expand Up @@ -246,8 +256,8 @@ impl<T: IntoSquirrelArgs> SquirrelFn<T> {
}
}

impl<T: IntoSquirrelArgs> AsRef<SQHandle<SQClosure>> for SquirrelFn<T> {
fn as_ref(&self) -> &SQHandle<SQClosure> {
impl<'a, T: IntoSquirrelArgs> AsRef<SQHandle<'a, SQClosure>> for SquirrelFn<'a, T> {
fn as_ref(&self) -> &SQHandle<'a, SQClosure> {
&self.func
}
}
Expand Down
118 changes: 85 additions & 33 deletions src/high/squirrel_traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use crate::{
squirrelclasstypes::SQRESULT,
squirreldatatypes::{
SQArray, SQBool, SQClosure, SQFloat, SQFunctionProto, SQInteger, SQNativeClosure,
SQObject, SQObjectType, SQString, SQStructInstance, SQTable,
SQObject, SQObjectType, SQObjectValue, SQString, SQStructInstance, SQTable,
},
},
high::squirrel::SQHandle,
Expand Down Expand Up @@ -370,7 +370,7 @@ impl GetFromSquirrelVm for Option<&mut CPlayer> {
}
}

impl<T: IsSQObject> GetFromSquirrelVm for SQHandle<T> {
impl<'a, T: IsSQObject<'a>> GetFromSquirrelVm for SQHandle<'a, T> {
fn get_from_sqvm(
sqvm: NonNull<HSquirrelVM>,
sqfunctions: &SquirrelFunctions,
Expand All @@ -394,7 +394,7 @@ impl<T: IsSQObject> GetFromSquirrelVm for SQHandle<T> {
}
}

impl<T: IntoSquirrelArgs> GetFromSquirrelVm for SquirrelFn<T> {
impl<'a, T: IntoSquirrelArgs> GetFromSquirrelVm for SquirrelFn<'a, T> {
#[inline]
fn get_from_sqvm(
sqvm: NonNull<HSquirrelVM>,
Expand Down Expand Up @@ -483,7 +483,7 @@ impl GetFromSQObject for SQObject {
}
}

impl<T: IsSQObject> GetFromSQObject for SQHandle<T> {
impl<'a, T: IsSQObject<'a>> GetFromSQObject for SQHandle<'a, T> {
#[inline]
fn get_from_sqobject(obj: &SQObject) -> Self {
match Self::try_new(*obj) {
Expand All @@ -499,7 +499,7 @@ impl<T: IsSQObject> GetFromSQObject for SQHandle<T> {
}
}

impl<T: IntoSquirrelArgs> GetFromSQObject for SquirrelFn<T> {
impl<'a, T: IntoSquirrelArgs> GetFromSQObject for SquirrelFn<'a, T> {
#[inline]
fn get_from_sqobject(obj: &SQObject) -> Self {
SquirrelFn {
Expand Down Expand Up @@ -565,6 +565,17 @@ macro_rules! sqvm_name {
}
)*
};

( $( LIFE $t:ty = $sqty:literal );*; ) => {
$(
impl<'a> SQVMName for $t {
#[inline]
fn get_sqvm_name() -> String {
$sqty.to_string()
}
}
)*
};
}

/// the sqvm name of a type in rust
Expand All @@ -588,20 +599,23 @@ sqvm_name! {
bool = "bool";
Vector3 = "vector";
Option<&mut CPlayer> = "entity";
SQHandle<SQClosure> = "var";
SQHandle<SQTable> = "table";
SQHandle<SQString> = "string";
SQHandle<SQArray> = "array";
SQHandle<SQFloat> = "float";
SQHandle<SQInteger> = "int";
SQHandle<SQFunctionProto> = "var";
SQHandle<SQStructInstance> = "var";
SQHandle<SQBool> = "bool";
SQHandle<SQNativeClosure> = "var";
SQObject = "var";
() = "void";
}

sqvm_name! {
LIFE SQHandle<'a, SQClosure> = "var";
LIFE SQHandle<'a, SQTable> = "table";
LIFE SQHandle<'a, SQString> = "string";
LIFE SQHandle<'a, SQArray> = "array";
LIFE SQHandle<'a, SQFloat> = "float";
LIFE SQHandle<'a, SQInteger> = "int";
LIFE SQHandle<'a, SQFunctionProto> = "var";
LIFE SQHandle<'a, SQStructInstance> = "var";
LIFE SQHandle<'a, SQBool> = "bool";
LIFE SQHandle<'a, SQNativeClosure> = "var";
}

sqvm_name! {
(T1: v2);
(T1: v1, T2: v2);
Expand All @@ -615,7 +629,7 @@ sqvm_name! {
(T1: v1, T2: v2, T3: v3, T4: v4, T5: v5, T6: v6, T7: v7, T8: v8, T9: v9, T10: v10);
}

impl<T: SQVMName + IntoSquirrelArgs> SQVMName for SquirrelFn<T> {
impl<'a, T: SQVMName + IntoSquirrelArgs> SQVMName for SquirrelFn<'a, T> {
fn get_sqvm_name() -> String {
format!("void functionref({})", T::get_sqvm_name())
}
Expand Down Expand Up @@ -650,34 +664,72 @@ impl<T: SQVMName, E> SQVMName for Result<T, E> {
// Markers

macro_rules! is_sq_object {
( $( $object:ty,RT: $rt:expr,OT: $ot:expr );*; ) => { $(
( $( $object:ty,RT: $rt:expr,OT: $ot:expr, EXTRACT: * $extract:ident );*; ) => {
$(
impl<'a> IsSQObject<'a> for $object {
const OT_TYPE: SQObjectType = $ot;
const RT_TYPE: SQObjectType = $rt;

impl IsSQObject for $object {
const OT_TYPE: SQObjectType = $ot;
const RT_TYPE: SQObjectType = $rt;
}
)* }
fn extract_mut(val: &'a mut SQObjectValue) -> &'a mut Self {
unsafe { &mut *val.$extract } // asummed to be init
}

fn extract(val: &'a SQObjectValue) -> &'a Self {
unsafe { &*val.$extract } // asummed to be init
}
}
)*
};

( $( $object:ty,RT: $rt:expr,OT: $ot:expr, EXTRACT: $extract:ident );*; ) => {
$(
impl<'a> IsSQObject<'a> for $object {
const OT_TYPE: SQObjectType = $ot;
const RT_TYPE: SQObjectType = $rt;

fn extract_mut(val: &'a mut SQObjectValue) -> &'a mut Self {
unsafe { std::mem::transmute(&mut val.$extract) } // asummed to be init
}

fn extract(val: &'a SQObjectValue) -> &'a Self {
unsafe { std::mem::transmute(&val.$extract) } // asummed to be init
}
}
)*
}
}

/// trait to define SQObject types
pub trait IsSQObject {
pub trait IsSQObject<'a> {
/// ot type
const OT_TYPE: SQObjectType;
/// return type
const RT_TYPE: SQObjectType;

/// extracts the `Self` out of the SQObjectValue
///
/// this is unsafe if [`SQHandle`] wasn't used
fn extract(val: &'a SQObjectValue) -> &'a Self;

/// extracts the `Self` out of the SQObjectValue
///
/// this is unsafe if [`SQHandle`] wasn't used
fn extract_mut(val: &'a mut SQObjectValue) -> &'a mut Self;
}

is_sq_object! {
SQTable, RT: SQObjectType::RT_TABLE, OT: SQObjectType::OT_TABLE;
SQString, RT: SQObjectType::RT_STRING, OT: SQObjectType::OT_STRING;
SQFunctionProto, RT: SQObjectType::RT_FUNCPROTO, OT: SQObjectType::OT_FUNCPROTO;
SQClosure, RT: SQObjectType::RT_CLOSURE, OT: SQObjectType::OT_CLOSURE;
SQStructInstance, RT: SQObjectType::RT_INSTANCE, OT: SQObjectType::OT_INSTANCE;
SQNativeClosure, RT: SQObjectType::RT_NATIVECLOSURE, OT: SQObjectType::OT_NATIVECLOSURE;
SQArray, RT: SQObjectType::RT_ARRAY, OT: SQObjectType::OT_ARRAY;
SQFloat, RT: SQObjectType::RT_FLOAT, OT: SQObjectType::OT_FLOAT;
SQInteger, RT: SQObjectType::RT_INTEGER, OT: SQObjectType::OT_INTEGER;
SQBool, RT: SQObjectType::RT_BOOL, OT: SQObjectType::OT_BOOL;
SQTable, RT: SQObjectType::RT_TABLE, OT: SQObjectType::OT_TABLE, EXTRACT: * asTable;
SQString, RT: SQObjectType::RT_STRING, OT: SQObjectType::OT_STRING, EXTRACT: * asString;
SQFunctionProto, RT: SQObjectType::RT_FUNCPROTO, OT: SQObjectType::OT_FUNCPROTO, EXTRACT: * asFuncProto;
SQClosure, RT: SQObjectType::RT_CLOSURE, OT: SQObjectType::OT_CLOSURE, EXTRACT: * asClosure;
SQStructInstance, RT: SQObjectType::RT_INSTANCE, OT: SQObjectType::OT_INSTANCE, EXTRACT: * asStructInstance;
SQNativeClosure, RT: SQObjectType::RT_NATIVECLOSURE, OT: SQObjectType::OT_NATIVECLOSURE, EXTRACT: * asNativeClosure;
SQArray, RT: SQObjectType::RT_ARRAY, OT: SQObjectType::OT_ARRAY, EXTRACT: * asArray;
}
is_sq_object! {
SQFloat, RT: SQObjectType::RT_FLOAT, OT: SQObjectType::OT_FLOAT, EXTRACT: asFloat;
SQInteger, RT: SQObjectType::RT_INTEGER, OT: SQObjectType::OT_INTEGER, EXTRACT: asInteger;
SQBool, RT: SQObjectType::RT_BOOL, OT: SQObjectType::OT_BOOL, EXTRACT: asInteger;
} // not a thing? SQStructDef, RT: SQObjectType::, OT: SQObjectType::;

// TODO: so here is the idea
Expand Down

0 comments on commit 49e6381

Please sign in to comment.