Variant.pkg 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422
  1. $#include "Core/Variant.h"
  2. $#include "IO/VectorBuffer.h"
  3. enum VariantType
  4. {
  5. VAR_NONE = 0,
  6. VAR_INT,
  7. VAR_BOOL,
  8. VAR_FLOAT,
  9. VAR_VECTOR2,
  10. VAR_VECTOR3,
  11. VAR_VECTOR4,
  12. VAR_QUATERNION,
  13. VAR_COLOR,
  14. VAR_STRING,
  15. VAR_BUFFER,
  16. VAR_VOIDPTR,
  17. VAR_RESOURCEREF,
  18. VAR_RESOURCEREFLIST,
  19. VAR_VARIANTVECTOR,
  20. VAR_VARIANTMAP,
  21. VAR_INTRECT,
  22. VAR_INTVECTOR2,
  23. VAR_PTR,
  24. VAR_MATRIX3,
  25. VAR_MATRIX3X4,
  26. VAR_MATRIX4,
  27. VAR_DOUBLE,
  28. VAR_STRINGVECTOR,
  29. MAX_VAR_TYPES
  30. };
  31. struct ResourceRef
  32. {
  33. ResourceRef();
  34. ResourceRef(StringHash type);
  35. ResourceRef(StringHash type, String name);
  36. ResourceRef(const ResourceRef& rhs);
  37. ~ResourceRef();
  38. StringHash type_ @ type;
  39. String name_ @ name;
  40. bool operator ==(const ResourceRef& rhs) const;
  41. };
  42. struct ResourceRefList
  43. {
  44. ResourceRefList();
  45. ResourceRefList(StringHash type);
  46. ~ResourceRefList();
  47. StringHash type_ @ type;
  48. bool operator ==(const ResourceRefList& rhs) const;
  49. };
  50. class Variant
  51. {
  52. static void _Setup(const char* type);
  53. // NOTE: do not change the constructor overloads order without also changing the manually coded implementation below
  54. Variant();
  55. Variant(const Variant& value); // This overload works for all Lua types that are convertible into a Variant
  56. Variant(const char* type, const char* value); // For storing a numerical type into Variant , value could be just a number
  57. Variant(VariantType type, const char* value);
  58. ~Variant();
  59. void Clear();
  60. bool operator ==(const Variant& rhs) const; // rhs can be any Lua types convertible into a Variant
  61. void Set(const Variant& rhs); // rhs can be any Lua types convertible into a Variant
  62. void* Get(const char* type = 0) const; // "Generic" get which is only possible in Lua scripting
  63. // All below getters are preserved for backward compatibility and for compatibility with C++ and AngelScript API
  64. int GetInt() const;
  65. unsigned GetUInt() const;
  66. StringHash GetStringHash() const;
  67. bool GetBool() const;
  68. float GetFloat() const;
  69. double GetDouble() const;
  70. const Vector2& GetVector2() const;
  71. const Vector3& GetVector3() const;
  72. const Vector4& GetVector4() const;
  73. const Quaternion& GetQuaternion() const;
  74. const Color& GetColor() const;
  75. const String GetString() const;
  76. const PODVector<unsigned char>& GetBuffer @ GetRawBuffer() const;
  77. VectorBuffer GetVectorBuffer @ GetBuffer() const; // For backward compatibility reason, keep the old alias
  78. void* GetVoidPtr(const char* type) const;
  79. const ResourceRef& GetResourceRef() const;
  80. const ResourceRefList& GetResourceRefList() const;
  81. const Vector<Variant>& GetVariantVector() const;
  82. const VariantMap& GetVariantMap() const;
  83. const Vector<String>& GetStringVector() const;
  84. const IntRect& GetIntRect() const;
  85. const IntVector2& GetIntVector2() const;
  86. RefCounted* GetPtr(const char* type) const;
  87. const Matrix3& GetMatrix3() const;
  88. const Matrix3x4& GetMatrix3x4() const;
  89. const Matrix4& GetMatrix4() const;
  90. VariantType GetType() const;
  91. String GetTypeName() const;
  92. String ToString() const;
  93. bool IsZero() const;
  94. bool IsEmpty() const;
  95. tolua_readonly tolua_property__get_set VariantType type;
  96. tolua_readonly tolua_property__get_set String typeName;
  97. tolua_readonly tolua_property__is_set bool zero;
  98. tolua_readonly tolua_property__is_set bool empty;
  99. };
  100. $[
  101. -- Call the setup method and then hide it immediately
  102. Variant:_Setup("Variant")
  103. Variant:_Setup("const Variant")
  104. Variant._Setup = nil
  105. $]
  106. ${
  107. static int VariantToStringEventHandler(lua_State* tolua_S)
  108. {
  109. lua_pushstring(tolua_S, static_cast<Variant*>(tolua_tousertype(tolua_S, -1, 0))->ToString().CString());
  110. return 1;
  111. }
  112. static int VariantConcatEventHandler(lua_State* tolua_S)
  113. {
  114. // __concat event handler has two operands, check whether the first operand is variant or the second is (one of them must be)
  115. // This event handler has two code branches to handle both cases differently based on the isFirst flag
  116. // In case of both operands are variant then the handler handles the case as if it is isFirst case then below lua_concat() call
  117. // would in turn trigger the handler the second time to handle the second operand using the !isFirst code branch
  118. bool isFirst = lua_isuserdata(tolua_S, 1);
  119. if (isFirst)
  120. lua_pushvalue(tolua_S, 1); // isFirst stack: variant1 operand2 variant1
  121. VariantToStringEventHandler(tolua_S); // isFirst stack: variant1 operand2 variant1 string1 | !isFirst: operand1 variant2 string2
  122. if (isFirst)
  123. {
  124. lua_replace(tolua_S, 1); // isFirst stack: string1 operand2 variant1
  125. lua_pop(tolua_S, 1); // isFirst stack: string1 operand2
  126. }
  127. else
  128. lua_remove(tolua_S, -2); // !isFirst stack: operand1 string2
  129. lua_concat(tolua_S, 2);
  130. return 1;
  131. }
  132. #define TOLUA_DISABLE_tolua_CoreLuaAPI_Variant__Setup00
  133. static int tolua_CoreLuaAPI_Variant__Setup00(lua_State* tolua_S)
  134. {
  135. // Register our own version of metamethod to handle __tostring and __concat events
  136. luaL_getmetatable(tolua_S, tolua_tostring(tolua_S, 2, 0));
  137. lua_pushstring(tolua_S, "__tostring");
  138. lua_pushcfunction(tolua_S, VariantToStringEventHandler);
  139. lua_rawset(tolua_S, -3);
  140. lua_pushstring(tolua_S, "__concat");
  141. lua_pushcfunction(tolua_S, VariantConcatEventHandler);
  142. lua_rawset(tolua_S, -3);
  143. lua_pop(tolua_S, 1);
  144. return 0;
  145. }
  146. // NOTE: the index number must match with the above variant constructor overloads order)
  147. // Forward declaration
  148. static int tolua_CoreLuaAPI_Variant_new00(lua_State* tolua_S);
  149. static int tolua_CoreLuaAPI_Variant_new00_local(lua_State* tolua_S);
  150. static bool VariantNewImpl(lua_State* tolua_S, bool gc)
  151. {
  152. tolua_Error tolua_err;
  153. if (tolua_isusertable(tolua_S, 1, "Variant", 0, &tolua_err) && lua_gettop(tolua_S) == 2)
  154. {
  155. Variant* tolua_ret = Mtolua_new(Variant());
  156. ToluaToVariant(tolua_S, 2, 0, *tolua_ret);
  157. tolua_pushusertype(tolua_S, static_cast<void*>(tolua_ret), "Variant");
  158. if (gc)
  159. tolua_register_gc(tolua_S, lua_gettop(tolua_S));
  160. return true;
  161. }
  162. return false;
  163. }
  164. #define TOLUA_DISABLE_tolua_CoreLuaAPI_Variant_new01
  165. static int tolua_CoreLuaAPI_Variant_new01(lua_State* tolua_S)
  166. {
  167. return VariantNewImpl(tolua_S, false) ? 1 : tolua_CoreLuaAPI_Variant_new00(tolua_S);
  168. }
  169. #define TOLUA_DISABLE_tolua_CoreLuaAPI_Variant_new01_local
  170. static int tolua_CoreLuaAPI_Variant_new01_local(lua_State* tolua_S)
  171. {
  172. return VariantNewImpl(tolua_S, true) ? 1 : tolua_CoreLuaAPI_Variant_new00_local(tolua_S);
  173. }
  174. #define TOLUA_DISABLE_tolua_CoreLuaAPI_Variant__eq00
  175. static int tolua_CoreLuaAPI_Variant__eq00(lua_State* tolua_S)
  176. {
  177. #ifndef TOLUA_RELEASE
  178. tolua_Error tolua_err;
  179. if (tolua_isusertype(tolua_S, 1, "const Variant", 0, &tolua_err) && lua_gettop(tolua_S) == 2)
  180. #endif
  181. {
  182. const Variant* self = static_cast<const Variant*>(tolua_tousertype(tolua_S, 1, 0));
  183. Variant rhs;
  184. ToluaToVariant(tolua_S, 2, 0, rhs);
  185. #ifndef TOLUA_RELEASE
  186. if (!self)
  187. tolua_error(tolua_S, "invalid 'self' in function 'operator=='", NULL);
  188. else
  189. #endif
  190. {
  191. tolua_pushboolean(tolua_S, self->operator ==(rhs));
  192. return 1;
  193. }
  194. }
  195. #ifndef TOLUA_RELEASE
  196. tolua_error(tolua_S, "#ferror in function '.eq'.", &tolua_err);
  197. return 0;
  198. #endif
  199. }
  200. #define TOLUA_DISABLE_tolua_CoreLuaAPI_Variant_Set00
  201. static int tolua_CoreLuaAPI_Variant_Set00(lua_State* tolua_S)
  202. {
  203. #ifndef TOLUA_RELEASE
  204. tolua_Error tolua_err;
  205. if (tolua_isusertype(tolua_S, 1, "Variant", 0, &tolua_err) && lua_gettop(tolua_S) == 2)
  206. #endif
  207. {
  208. Variant * self = static_cast<Variant*>(tolua_tousertype(tolua_S, 1, 0));
  209. Variant rhs;
  210. ToluaToVariant(tolua_S, 2, 0, rhs);
  211. const char* type = tolua_tostring(tolua_S, 3, 0);
  212. #ifndef TOLUA_RELEASE
  213. if (!self)
  214. tolua_error(tolua_S, "invalid 'self' in function 'Set'", NULL);
  215. else
  216. #endif
  217. {
  218. *self = rhs;
  219. return 0;
  220. }
  221. }
  222. #ifndef TOLUA_RELEASE
  223. tolua_error(tolua_S, "#ferror in function 'Set'.", &tolua_err);
  224. return 0;
  225. #endif
  226. }
  227. #define TOLUA_DISABLE_tolua_CoreLuaAPI_Variant_Get00
  228. static int tolua_CoreLuaAPI_Variant_Get00(lua_State* tolua_S)
  229. {
  230. #ifndef TOLUA_RELEASE
  231. tolua_Error tolua_err;
  232. if (tolua_isusertype(tolua_S, 1, "const Variant", 0, &tolua_err) && tolua_isstring(tolua_S, 2, 1, &tolua_err) &&
  233. tolua_isnoobj(tolua_S, 3, &tolua_err))
  234. #endif
  235. {
  236. const Variant* self = static_cast<const Variant*>(tolua_tousertype(tolua_S, 1, 0));
  237. const char* type = tolua_tostring(tolua_S, 2, 0);
  238. #ifndef TOLUA_RELEASE
  239. if (!self)
  240. tolua_error(tolua_S, "invalid 'self' in function 'Get'", NULL);
  241. else
  242. #endif
  243. {
  244. ToluaPushVariant(tolua_S, self, type);
  245. return 1;
  246. }
  247. }
  248. #ifndef TOLUA_RELEASE
  249. tolua_error(tolua_S, "#ferror in function 'Get'.", &tolua_err);
  250. return 0;
  251. #endif
  252. }
  253. #define TOLUA_DISABLE_tolua_CoreLuaAPI_Variant_GetVoidPtr00
  254. static int tolua_CoreLuaAPI_Variant_GetVoidPtr00(lua_State* tolua_S)
  255. {
  256. #ifndef TOLUA_RELEASE
  257. tolua_Error tolua_err;
  258. if (
  259. !tolua_isusertype(tolua_S,1,"const Variant",0,&tolua_err) ||
  260. !tolua_isstring(tolua_S,2,0,&tolua_err) ||
  261. !tolua_isnoobj(tolua_S,3,&tolua_err)
  262. )
  263. goto tolua_lerror;
  264. else
  265. #endif
  266. {
  267. const Variant* self = (const Variant*) tolua_tousertype(tolua_S,1,0);
  268. const char* type = ((const char*) tolua_tostring(tolua_S,2,0));
  269. #ifndef TOLUA_RELEASE
  270. if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GetVoidPtr'", NULL);
  271. #endif
  272. {
  273. // Use the safer version which first check the type provided through Lua script to prevent VM crashes on invalid type
  274. ToluaPushRegisteredUserType(tolua_S, static_cast<void*>(self->GetVoidPtr()), type);
  275. }
  276. }
  277. return 1;
  278. #ifndef TOLUA_RELEASE
  279. tolua_lerror:
  280. tolua_error(tolua_S,"#ferror in function 'GetVoidPtr'.",&tolua_err);
  281. return 0;
  282. #endif
  283. }
  284. #define TOLUA_DISABLE_tolua_CoreLuaAPI_Variant_GetPtr00
  285. static int tolua_CoreLuaAPI_Variant_GetPtr00(lua_State* tolua_S)
  286. {
  287. #ifndef TOLUA_RELEASE
  288. tolua_Error tolua_err;
  289. if (
  290. !tolua_isusertype(tolua_S,1,"const Variant",0,&tolua_err) ||
  291. !tolua_isstring(tolua_S,2,1,&tolua_err) ||
  292. !tolua_isnoobj(tolua_S,3,&tolua_err)
  293. )
  294. goto tolua_lerror;
  295. else
  296. #endif
  297. {
  298. const Variant* self = (const Variant*) tolua_tousertype(tolua_S,1,0);
  299. const char* type = ((const char*) tolua_tostring(tolua_S,2,0));
  300. #ifndef TOLUA_RELEASE
  301. if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GetPtr'", NULL);
  302. #endif
  303. {
  304. ToluaPushRegisteredUserType(tolua_S, static_cast<void*>(self->GetPtr()), type);
  305. }
  306. }
  307. return 1;
  308. #ifndef TOLUA_RELEASE
  309. tolua_lerror:
  310. tolua_error(tolua_S,"#ferror in function 'GetPtr'.",&tolua_err);
  311. return 0;
  312. #endif
  313. }
  314. $}
  315. class VariantMap
  316. {
  317. static void _Setup(const char* type);
  318. VariantMap();
  319. ~VariantMap();
  320. };
  321. $[
  322. VariantMap:_Setup("VariantMap")
  323. VariantMap:_Setup("const VariantMap")
  324. VariantMap._Setup = nil
  325. $]
  326. ${
  327. static int VariantMapIndexEventHandler(lua_State* tolua_S)
  328. {
  329. int t = lua_type(tolua_S, 2);
  330. StringHash key;
  331. if (t == LUA_TSTRING)
  332. key = StringHash(lua_tostring(tolua_S, 2));
  333. else if (t == LUA_TNUMBER)
  334. key = StringHash((unsigned)lua_tonumber(tolua_S, 2));
  335. else if (t == LUA_TUSERDATA)
  336. {
  337. tolua_Error error;
  338. if (tolua_isusertype(tolua_S, 2, "StringHash", 0, &error))
  339. key = *static_cast<StringHash*>(tolua_tousertype(tolua_S, 2, 0));
  340. }
  341. Variant* variant = key ? static_cast<const VariantMap*>(tolua_tousertype(tolua_S, 1, 0))->operator [](key) : 0;
  342. if (variant)
  343. tolua_pushusertype(tolua_S, variant, "Variant");
  344. else
  345. lua_pushnil(tolua_S);
  346. return 1;
  347. }
  348. static int VariantMapNewIndexEventHandler(lua_State* tolua_S)
  349. {
  350. int t = lua_type(tolua_S, 2);
  351. StringHash key;
  352. if (t == LUA_TSTRING)
  353. key = StringHash(lua_tostring(tolua_S, 2));
  354. else if (t == LUA_TNUMBER)
  355. key = StringHash((unsigned)lua_tonumber(tolua_S, 2));
  356. else if (t == LUA_TUSERDATA)
  357. {
  358. tolua_Error error;
  359. if (tolua_isusertype(tolua_S, 2, "StringHash", 0, &error))
  360. key = *static_cast<StringHash*>(tolua_tousertype(tolua_S, 2, 0));
  361. else
  362. return 0;
  363. }
  364. else
  365. return 0;
  366. Variant& variant = static_cast<VariantMap*>(tolua_tousertype(tolua_S, 1, 0))->operator [](key); // autovivification
  367. ToluaToVariant(tolua_S, 3, 0, variant);
  368. return 0;
  369. }
  370. #define TOLUA_DISABLE_tolua_CoreLuaAPI_VariantMap__Setup00
  371. static int tolua_CoreLuaAPI_VariantMap__Setup00(lua_State* tolua_S)
  372. {
  373. // Register our own version of metamethod to handle __index and __newindex events
  374. luaL_getmetatable(tolua_S, tolua_tostring(tolua_S, 2, 0));
  375. lua_pushstring(tolua_S, "__index");
  376. lua_pushcfunction(tolua_S, VariantMapIndexEventHandler);
  377. lua_rawset(tolua_S, -3);
  378. lua_pushstring(tolua_S, "__newindex");
  379. lua_pushcfunction(tolua_S, VariantMapNewIndexEventHandler);
  380. lua_rawset(tolua_S, -3);
  381. lua_pop(tolua_S, 1);
  382. return 0;
  383. }
  384. $}