Variant.pkg 14 KB

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