diff --git a/src/high/squirrel.rs b/src/high/squirrel.rs index 21ece4e..cf50c0f 100644 --- a/src/high/squirrel.rs +++ b/src/high/squirrel.rs @@ -133,16 +133,16 @@ impl CSquirrelVMHandle { } /// runtime check for [`SQObject`] types -pub struct SQHandle { +pub struct SQHandle<'a, H: IsSQObject<'a>> { inner: SQObject, - marker: PhantomData, + marker: PhantomData<&'a H>, } -impl SQHandle { +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 { let ty = value._Type; - if ty == H::OT_TYPE || ty == H::RT_TYPE { + if ty == H::OT_TYPE { Ok(Self { inner: value, marker: PhantomData, @@ -164,22 +164,32 @@ impl SQHandle { } /// 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 { +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 @@ -187,18 +197,18 @@ impl SQHandle { } /// provides invariance for calling squirrel functions with little overhead -pub struct SquirrelFn { - pub(crate) func: SQHandle, +pub struct SquirrelFn<'a, T: IntoSquirrelArgs> { + pub(crate) func: SQHandle<'a, SQClosure>, pub(crate) phantom: PhantomData<*mut T>, } -impl SquirrelFn { +impl<'a, T: IntoSquirrelArgs> SquirrelFn<'a, T> { /// creates a new [`SquirrelFn`] using the invariance of [`SQHandle`] /// /// # Safety /// /// doesn't check if the function passed has the correct args and return type - pub const unsafe fn new_unchecked(obj: SQHandle) -> Self { + pub const unsafe fn new_unchecked(obj: SQHandle<'a, SQClosure>) -> Self { Self { func: obj, phantom: PhantomData, @@ -246,8 +256,8 @@ impl SquirrelFn { } } -impl AsRef> for SquirrelFn { - fn as_ref(&self) -> &SQHandle { +impl<'a, T: IntoSquirrelArgs> AsRef> for SquirrelFn<'a, T> { + fn as_ref(&self) -> &SQHandle<'a, SQClosure> { &self.func } } diff --git a/src/high/squirrel_traits.rs b/src/high/squirrel_traits.rs index 5dd5b1c..0844ce3 100644 --- a/src/high/squirrel_traits.rs +++ b/src/high/squirrel_traits.rs @@ -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, @@ -370,7 +370,7 @@ impl GetFromSquirrelVm for Option<&mut CPlayer> { } } -impl GetFromSquirrelVm for SQHandle { +impl<'a, T: IsSQObject<'a>> GetFromSquirrelVm for SQHandle<'a, T> { fn get_from_sqvm( sqvm: NonNull, sqfunctions: &SquirrelFunctions, @@ -394,7 +394,7 @@ impl GetFromSquirrelVm for SQHandle { } } -impl GetFromSquirrelVm for SquirrelFn { +impl<'a, T: IntoSquirrelArgs> GetFromSquirrelVm for SquirrelFn<'a, T> { #[inline] fn get_from_sqvm( sqvm: NonNull, @@ -483,7 +483,7 @@ impl GetFromSQObject for SQObject { } } -impl GetFromSQObject for SQHandle { +impl<'a, T: IsSQObject<'a>> GetFromSQObject for SQHandle<'a, T> { #[inline] fn get_from_sqobject(obj: &SQObject) -> Self { match Self::try_new(*obj) { @@ -499,7 +499,7 @@ impl GetFromSQObject for SQHandle { } } -impl GetFromSQObject for SquirrelFn { +impl<'a, T: IntoSquirrelArgs> GetFromSQObject for SquirrelFn<'a, T> { #[inline] fn get_from_sqobject(obj: &SQObject) -> Self { SquirrelFn { @@ -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 @@ -588,20 +599,23 @@ sqvm_name! { bool = "bool"; Vector3 = "vector"; Option<&mut CPlayer> = "entity"; - SQHandle = "var"; - SQHandle = "table"; - SQHandle = "string"; - SQHandle = "array"; - SQHandle = "float"; - SQHandle = "int"; - SQHandle = "var"; - SQHandle = "var"; - SQHandle = "bool"; - SQHandle = "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); @@ -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 SQVMName for SquirrelFn { +impl<'a, T: SQVMName + IntoSquirrelArgs> SQVMName for SquirrelFn<'a, T> { fn get_sqvm_name() -> String { format!("void functionref({})", T::get_sqvm_name()) } @@ -650,34 +664,72 @@ impl SQVMName for Result { // 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