$#include "Core/Variant.h" $#include "IO/VectorBuffer.h" enum VariantType { VAR_NONE = 0, VAR_INT, VAR_BOOL, VAR_FLOAT, VAR_VECTOR2, VAR_VECTOR3, VAR_VECTOR4, VAR_QUATERNION, VAR_COLOR, VAR_STRING, VAR_BUFFER, VAR_VOIDPTR, VAR_RESOURCEREF, VAR_RESOURCEREFLIST, VAR_VARIANTVECTOR, VAR_VARIANTMAP, VAR_INTRECT, VAR_INTVECTOR2, VAR_PTR, VAR_MATRIX3, VAR_MATRIX3X4, VAR_MATRIX4, VAR_DOUBLE, VAR_STRINGVECTOR, VAR_RECT, VAR_INTVECTOR3, VAR_INT64, MAX_VAR_TYPES }; struct ResourceRef { ResourceRef(); ResourceRef(StringHash type); ResourceRef(StringHash type, String name); ResourceRef(String type, String name); ResourceRef(const ResourceRef& rhs); ~ResourceRef(); StringHash type_ @ type; String name_ @ name; bool operator ==(const ResourceRef& rhs) const; }; struct ResourceRefList { ResourceRefList(); ResourceRefList(StringHash type); ~ResourceRefList(); StringHash type_ @ type; bool operator ==(const ResourceRefList& rhs) const; }; class Variant { static void _Setup(const char* type); // NOTE: do not change the constructor overloads order without also changing the manually coded implementation below Variant(); Variant(const Variant& value); // This overload works for all Lua types that are convertible into a Variant Variant(const char* type, const char* value); // For storing a numerical type into Variant , value could be just a number Variant(VariantType type, const char* value); ~Variant(); void Clear(); bool operator ==(const Variant& rhs) const; // rhs can be any Lua types convertible into a Variant void Set(const Variant& rhs); // rhs can be any Lua types convertible into a Variant void* Get(const char* type = 0) const; // "Generic" get which is only possible in Lua scripting // All below getters are preserved for backward compatibility and for compatibility with C++ and AngelScript API int GetInt() const; unsigned GetUInt() const; long long int GetInt64() const; unsigned long long int GetUInt64() const; StringHash GetStringHash() const; bool GetBool() const; float GetFloat() const; double GetDouble() const; const Vector2& GetVector2() const; const Vector3& GetVector3() const; const Vector4& GetVector4() const; const Quaternion& GetQuaternion() const; const Color& GetColor() const; const String GetString() const; const PODVector& GetBuffer @ GetRawBuffer() const; VectorBuffer GetVectorBuffer @ GetBuffer() const; // For backward compatibility reason, keep the old alias void* GetVoidPtr(const char* type) const; const ResourceRef& GetResourceRef() const; const ResourceRefList& GetResourceRefList() const; const Vector& GetVariantVector() const; const VariantMap& GetVariantMap() const; const Vector& GetStringVector() const; const Rect& GetRect() const; const IntRect& GetIntRect() const; const IntVector2& GetIntVector2() const; const IntVector3& GetIntVector3() const; RefCounted* GetPtr(const char* type) const; const Matrix3& GetMatrix3() const; const Matrix3x4& GetMatrix3x4() const; const Matrix4& GetMatrix4() const; VariantType GetType() const; String GetTypeName() const; String ToString() const; bool IsZero() const; bool IsEmpty() const; tolua_readonly tolua_property__get_set VariantType type; tolua_readonly tolua_property__get_set String typeName; tolua_readonly tolua_property__is_set bool zero; tolua_readonly tolua_property__is_set bool empty; }; $[ -- Call the setup method and then hide it immediately Variant:_Setup("Variant") Variant:_Setup("const Variant") Variant._Setup = nil $] ${ static int VariantToStringEventHandler(lua_State* tolua_S) { lua_pushstring(tolua_S, static_cast(tolua_tousertype(tolua_S, -1, 0))->ToString().CString()); return 1; } static int VariantConcatEventHandler(lua_State* tolua_S) { // __concat event handler has two operands, check whether the first operand is variant or the second is (one of them must be) // This event handler has two code branches to handle both cases differently based on the isFirst flag // In case of both operands are variant then the handler handles the case as if it is isFirst case then below lua_concat() call // would in turn trigger the handler the second time to handle the second operand using the !isFirst code branch bool isFirst = lua_isuserdata(tolua_S, 1); if (isFirst) lua_pushvalue(tolua_S, 1); // isFirst stack: variant1 operand2 variant1 VariantToStringEventHandler(tolua_S); // isFirst stack: variant1 operand2 variant1 string1 | !isFirst: operand1 variant2 string2 if (isFirst) { lua_replace(tolua_S, 1); // isFirst stack: string1 operand2 variant1 lua_pop(tolua_S, 1); // isFirst stack: string1 operand2 } else lua_remove(tolua_S, -2); // !isFirst stack: operand1 string2 lua_concat(tolua_S, 2); return 1; } #define TOLUA_DISABLE_tolua_CoreLuaAPI_Variant__Setup00 static int tolua_CoreLuaAPI_Variant__Setup00(lua_State* tolua_S) { // Register our own version of metamethod to handle __tostring and __concat events luaL_getmetatable(tolua_S, tolua_tostring(tolua_S, 2, 0)); lua_pushstring(tolua_S, "__tostring"); lua_pushcfunction(tolua_S, VariantToStringEventHandler); lua_rawset(tolua_S, -3); lua_pushstring(tolua_S, "__concat"); lua_pushcfunction(tolua_S, VariantConcatEventHandler); lua_rawset(tolua_S, -3); lua_pop(tolua_S, 1); return 0; } // NOTE: the index number must match with the above variant constructor overloads order) // Forward declaration static int tolua_CoreLuaAPI_Variant_new00(lua_State* tolua_S); static int tolua_CoreLuaAPI_Variant_new00_local(lua_State* tolua_S); static bool VariantNewImpl(lua_State* tolua_S, bool gc) { tolua_Error tolua_err; if (tolua_isusertable(tolua_S, 1, "Variant", 0, &tolua_err) && lua_gettop(tolua_S) == 2) { Variant* tolua_ret = Mtolua_new(Variant()); ToluaToVariant(tolua_S, 2, 0, *tolua_ret); tolua_pushusertype(tolua_S, static_cast(tolua_ret), "Variant"); if (gc) tolua_register_gc(tolua_S, lua_gettop(tolua_S)); return true; } return false; } #define TOLUA_DISABLE_tolua_CoreLuaAPI_Variant_new01 static int tolua_CoreLuaAPI_Variant_new01(lua_State* tolua_S) { return VariantNewImpl(tolua_S, false) ? 1 : tolua_CoreLuaAPI_Variant_new00(tolua_S); } #define TOLUA_DISABLE_tolua_CoreLuaAPI_Variant_new01_local static int tolua_CoreLuaAPI_Variant_new01_local(lua_State* tolua_S) { return VariantNewImpl(tolua_S, true) ? 1 : tolua_CoreLuaAPI_Variant_new00_local(tolua_S); } #define TOLUA_DISABLE_tolua_CoreLuaAPI_Variant__eq00 static int tolua_CoreLuaAPI_Variant__eq00(lua_State* tolua_S) { #ifndef TOLUA_RELEASE tolua_Error tolua_err; if (tolua_isusertype(tolua_S, 1, "const Variant", 0, &tolua_err) && lua_gettop(tolua_S) == 2) #endif { const Variant* self = static_cast(tolua_tousertype(tolua_S, 1, 0)); Variant rhs; ToluaToVariant(tolua_S, 2, 0, rhs); #ifndef TOLUA_RELEASE if (!self) tolua_error(tolua_S, "invalid 'self' in function 'operator=='", NULL); else #endif { tolua_pushboolean(tolua_S, self->operator ==(rhs)); return 1; } } #ifndef TOLUA_RELEASE tolua_error(tolua_S, "#ferror in function '.eq'.", &tolua_err); return 0; #endif } #define TOLUA_DISABLE_tolua_CoreLuaAPI_Variant_Set00 static int tolua_CoreLuaAPI_Variant_Set00(lua_State* tolua_S) { #ifndef TOLUA_RELEASE tolua_Error tolua_err; if (tolua_isusertype(tolua_S, 1, "Variant", 0, &tolua_err) && lua_gettop(tolua_S) == 2) #endif { Variant * self = static_cast(tolua_tousertype(tolua_S, 1, 0)); Variant rhs; ToluaToVariant(tolua_S, 2, 0, rhs); const char* type = tolua_tostring(tolua_S, 3, 0); #ifndef TOLUA_RELEASE if (!self) tolua_error(tolua_S, "invalid 'self' in function 'Set'", NULL); else #endif { *self = rhs; return 0; } } #ifndef TOLUA_RELEASE tolua_error(tolua_S, "#ferror in function 'Set'.", &tolua_err); return 0; #endif } #define TOLUA_DISABLE_tolua_CoreLuaAPI_Variant_Get00 static int tolua_CoreLuaAPI_Variant_Get00(lua_State* tolua_S) { #ifndef TOLUA_RELEASE tolua_Error tolua_err; if (tolua_isusertype(tolua_S, 1, "const Variant", 0, &tolua_err) && tolua_isstring(tolua_S, 2, 1, &tolua_err) && tolua_isnoobj(tolua_S, 3, &tolua_err)) #endif { const Variant* self = static_cast(tolua_tousertype(tolua_S, 1, 0)); const char* type = tolua_tostring(tolua_S, 2, 0); #ifndef TOLUA_RELEASE if (!self) tolua_error(tolua_S, "invalid 'self' in function 'Get'", NULL); else #endif { ToluaPushVariant(tolua_S, self, type); return 1; } } #ifndef TOLUA_RELEASE tolua_error(tolua_S, "#ferror in function 'Get'.", &tolua_err); return 0; #endif } #define TOLUA_DISABLE_tolua_CoreLuaAPI_Variant_GetVoidPtr00 static int tolua_CoreLuaAPI_Variant_GetVoidPtr00(lua_State* tolua_S) { #ifndef TOLUA_RELEASE tolua_Error tolua_err; if ( !tolua_isusertype(tolua_S,1,"const Variant",0,&tolua_err) || !tolua_isstring(tolua_S,2,0,&tolua_err) || !tolua_isnoobj(tolua_S,3,&tolua_err) ) goto tolua_lerror; else #endif { const Variant* self = (const Variant*) tolua_tousertype(tolua_S,1,0); const char* type = ((const char*) tolua_tostring(tolua_S,2,0)); #ifndef TOLUA_RELEASE if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GetVoidPtr'", NULL); #endif { // Use the safer version which first check the type provided through Lua script to prevent VM crashes on invalid type ToluaPushRegisteredUserType(tolua_S, static_cast(self->GetVoidPtr()), type); } } return 1; #ifndef TOLUA_RELEASE tolua_lerror: tolua_error(tolua_S,"#ferror in function 'GetVoidPtr'.",&tolua_err); return 0; #endif } #define TOLUA_DISABLE_tolua_CoreLuaAPI_Variant_GetPtr00 static int tolua_CoreLuaAPI_Variant_GetPtr00(lua_State* tolua_S) { #ifndef TOLUA_RELEASE tolua_Error tolua_err; if ( !tolua_isusertype(tolua_S,1,"const Variant",0,&tolua_err) || !tolua_isstring(tolua_S,2,1,&tolua_err) || !tolua_isnoobj(tolua_S,3,&tolua_err) ) goto tolua_lerror; else #endif { const Variant* self = (const Variant*) tolua_tousertype(tolua_S,1,0); const char* type = ((const char*) tolua_tostring(tolua_S,2,0)); #ifndef TOLUA_RELEASE if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GetPtr'", NULL); #endif { ToluaPushRegisteredUserType(tolua_S, static_cast(self->GetPtr()), type); } } return 1; #ifndef TOLUA_RELEASE tolua_lerror: tolua_error(tolua_S,"#ferror in function 'GetPtr'.",&tolua_err); return 0; #endif } $} class VariantMap { static void _Setup(const char* type); VariantMap(); ~VariantMap(); }; $[ VariantMap:_Setup("VariantMap") VariantMap:_Setup("const VariantMap") VariantMap._Setup = nil $] ${ static int VariantMapIndexEventHandler(lua_State* tolua_S) { int t = lua_type(tolua_S, 2); StringHash key; if (t == LUA_TSTRING) key = StringHash(lua_tostring(tolua_S, 2)); else if (t == LUA_TNUMBER) key = StringHash((unsigned)lua_tonumber(tolua_S, 2)); else if (t == LUA_TUSERDATA) { tolua_Error error; if (tolua_isusertype(tolua_S, 2, "StringHash", 0, &error)) key = *static_cast(tolua_tousertype(tolua_S, 2, 0)); } Variant* variant = key ? static_cast(tolua_tousertype(tolua_S, 1, 0))->operator [](key) : 0; if (variant) tolua_pushusertype(tolua_S, variant, "Variant"); else lua_pushnil(tolua_S); return 1; } static int VariantMapNewIndexEventHandler(lua_State* tolua_S) { int t = lua_type(tolua_S, 2); StringHash key; if (t == LUA_TSTRING) key = StringHash(lua_tostring(tolua_S, 2)); else if (t == LUA_TNUMBER) key = StringHash((unsigned)lua_tonumber(tolua_S, 2)); else if (t == LUA_TUSERDATA) { tolua_Error error; if (tolua_isusertype(tolua_S, 2, "StringHash", 0, &error)) key = *static_cast(tolua_tousertype(tolua_S, 2, 0)); else return 0; } else return 0; Variant& variant = static_cast(tolua_tousertype(tolua_S, 1, 0))->operator [](key); // autovivification ToluaToVariant(tolua_S, 3, 0, variant); return 0; } #define TOLUA_DISABLE_tolua_CoreLuaAPI_VariantMap__Setup00 static int tolua_CoreLuaAPI_VariantMap__Setup00(lua_State* tolua_S) { // Register our own version of metamethod to handle __index and __newindex events luaL_getmetatable(tolua_S, tolua_tostring(tolua_S, 2, 0)); lua_pushstring(tolua_S, "__index"); lua_pushcfunction(tolua_S, VariantMapIndexEventHandler); lua_rawset(tolua_S, -3); lua_pushstring(tolua_S, "__newindex"); lua_pushcfunction(tolua_S, VariantMapNewIndexEventHandler); lua_rawset(tolua_S, -3); lua_pop(tolua_S, 1); return 0; } $}