Commits

Bart van Strien committed f4536f3

Add support for "flat" tables to Variant.

This means you can now use Variants (used by Channels and love.event, for instance) to send tables as long as they only contain keys and values supported by Variant, AND they are not tables themselves.

  • Participants
  • Parent commits c8b6002

Comments (0)

Files changed (2)

src/common/Variant.cpp

 	return t;
 }
 
+static inline void delete_table(std::vector<std::pair<Variant*, Variant*> > *table)
+{
+	while (!table->empty())
+	{
+		std::pair<Variant*, Variant*> &kv = table->back();
+		kv.first->release();
+		kv.second->release();
+		table->pop_back();
+	}
+	delete table;
+}
+
 Variant::Variant()
 	: type(NIL)
 	, data()
 		data.userdata = userdata;
 }
 
+// Variant gets ownership of the vector.
+Variant::Variant(std::vector<std::pair<Variant*, Variant*> > *table)
+	: type(TABLE)
+{
+	data.table = table;
+}
+
 Variant::~Variant()
 {
 	switch (type)
 	case FUSERDATA:
 		((love::Object *) data.userdata)->release();
 		break;
+	case TABLE:
+		delete_table(data.table);
 	default:
 		break;
 	}
 }
 
-Variant *Variant::fromLua(lua_State *L, int n)
+Variant *Variant::fromLua(lua_State *L, int n, bool allowTables)
 {
 	Variant *v = NULL;
 	size_t len;
 	const char *str;
+	if (n < 0) // Fix the stack position, we might modify it later
+		n += lua_gettop(L) + 1;
+
 	switch (lua_type(L, n))
 	{
 	case LUA_TBOOLEAN:
 	case LUA_TNIL:
 		v = new Variant();
 		break;
+	case LUA_TTABLE:
+		if (allowTables)
+		{
+			bool success = true;
+			std::vector<std::pair<Variant*, Variant*> > *table = new std::vector<std::pair<Variant*, Variant*> >();
+			lua_pushnil(L);
+			while (lua_next(L, n))
+			{
+				Variant *key = fromLua(L, -2, false);
+				if (!key)
+				{
+					success = false;
+					lua_pop(L, 2);
+					break;
+				}
+
+				Variant *value = fromLua(L, -1, false);
+				if (!value)
+				{
+					delete key;
+					success = false;
+					lua_pop(L, 2);
+					break;
+				}
+
+				table->push_back(std::make_pair(key, value));
+
+				lua_pop(L, 1);
+			}
+
+			if (success)
+				v = new Variant(table);
+			else
+				delete_table(table);
+		}
+		break;
 	}
 	return v;
 }
 		// sadly, however, it's the most
 		// I can do (at the moment).
 		break;
+	case TABLE:
+		lua_newtable(L);
+		for (int i = 0; i < data.table->size(); ++i)
+		{
+			std::pair<Variant*, Variant*> &kv = data.table->at(i);
+			kv.first->toLua(L);
+			kv.second->toLua(L);
+			lua_settable(L, -3);
+		}
+		break;
 	case NIL:
 	default:
 		lua_pushnil(L);

src/common/Variant.h

 #include "common/Object.h"
 
 #include <cstring>
+#include <vector>
+#include <utility>
 
 namespace love
 {
 	Variant(char c);
 	Variant(void *userdata);
 	Variant(love::Type udatatype, void *userdata);
+	Variant(std::vector<std::pair<Variant*, Variant*> > *table);
 	virtual ~Variant();
 
-	static Variant *fromLua(lua_State *L, int n);
+	static Variant *fromLua(lua_State *L, int n, bool allowTables = true);
 	void toLua(lua_State *L);
 
 private:
 		STRING,
 		LUSERDATA,
 		FUSERDATA,
-		NIL
+		NIL,
+		TABLE
 	} type;
 	union
 	{
 			size_t len;
 		} string;
 		void *userdata;
+		std::vector<std::pair<Variant*, Variant*> > *table;
 	} data;
 	love::Type udatatype;
 	bits flags;