Half finished with serialization routine
This commit is contained in:
@@ -217,13 +217,16 @@ int LuaTypeTagValue(lua_State *L) { return 0; }
|
|||||||
// Lua table types. These deliberately do not overlap
|
// Lua table types. These deliberately do not overlap
|
||||||
// with lua type values.
|
// with lua type values.
|
||||||
//
|
//
|
||||||
#define LUA_TT_GENERAL 16
|
enum LuaTableType {
|
||||||
#define LUA_TT_REGISTRY 17
|
LUA_TT_GENERAL = LUA_NUMTAGS,
|
||||||
#define LUA_TT_GLOBALENV 18
|
LUA_TT_REGISTRY,
|
||||||
#define LUA_TT_TANGIBLE 19
|
LUA_TT_GLOBALENV,
|
||||||
#define LUA_TT_TANGIBLEMETA 20
|
LUA_TT_TANGIBLE,
|
||||||
#define LUA_TT_GLOBALDB 21
|
LUA_TT_TANGIBLEMETA,
|
||||||
#define LUA_TT_CLASS 22
|
LUA_TT_CLASS,
|
||||||
|
|
||||||
|
LUA_TT_SENTINEL
|
||||||
|
};
|
||||||
|
|
||||||
// World types enum.
|
// World types enum.
|
||||||
|
|
||||||
|
|||||||
189
luprex/cpp/core/serializelua.cpp
Normal file
189
luprex/cpp/core/serializelua.cpp
Normal file
@@ -0,0 +1,189 @@
|
|||||||
|
#include "serializelua.hpp"
|
||||||
|
|
||||||
|
enum PackCodes {
|
||||||
|
LUA_PK_TRUE = LUA_TT_SENTINEL,
|
||||||
|
LUA_PK_FALSE,
|
||||||
|
LUA_PK_REFERENCE,
|
||||||
|
LUA_PK_ENDTABLE
|
||||||
|
};
|
||||||
|
|
||||||
|
class Deserializer {
|
||||||
|
LuaVar id_to_value_;
|
||||||
|
LuaStack LS_;
|
||||||
|
int next_id_;
|
||||||
|
eng::string &error_;
|
||||||
|
StreamBuffer *sb_;
|
||||||
|
|
||||||
|
Deserializer(LuaStack &LS0, LuaSlot val, StreamBuffer *sb, eng::string &error) :
|
||||||
|
LS_(LS0.state(), lookup_, value_to_id_), error_(error) {
|
||||||
|
next_id_ = 1;
|
||||||
|
LS_.newtable(id_to_value_);
|
||||||
|
try {
|
||||||
|
uint8_t b = sb_->read_uint8();
|
||||||
|
deserialize_r(b, val);
|
||||||
|
} catch (StreamEof e) {
|
||||||
|
error_ = "EOF reached while deserializing data";
|
||||||
|
LS_.set(val, LuaNil);
|
||||||
|
}
|
||||||
|
LS_.result();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// If the serialize routine encounters an error, it must set the
|
||||||
|
// error message string. In that case, it is assumed that the contents
|
||||||
|
// of the serialization buffer is no longer valid and there is no
|
||||||
|
// requirement to try to keep it valid.
|
||||||
|
|
||||||
|
class Serializer {
|
||||||
|
LuaVar lookup_;
|
||||||
|
LuaVar value_to_id_;
|
||||||
|
LuaStack LS_;
|
||||||
|
int next_id_;
|
||||||
|
eng::string &error_;
|
||||||
|
StreamBuffer *sb_;
|
||||||
|
|
||||||
|
void serialize_keyvals_r(LuaSlot tab) {
|
||||||
|
LuaVar key, val;
|
||||||
|
LuaStack SLS(LS_.state(), key, val);
|
||||||
|
SLS.getmetatable(val, tab);
|
||||||
|
if (!LS.isnil(val)) {
|
||||||
|
error_ = "Cannot serialize metatables";
|
||||||
|
SLS.result();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
sb_->pack_uint8(LUA_TT_GENERAL);
|
||||||
|
SLS.set(key, LuaNil);
|
||||||
|
while (LS.next(tab, key, val)) {
|
||||||
|
serialize_r(key);
|
||||||
|
if (!error_.empty()) {
|
||||||
|
SLS.result();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
serialize_r(val);
|
||||||
|
if (!error_.empty()) {
|
||||||
|
SLS.result();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sb_->pack_uint8(LUA_PK_ENDTABLE);
|
||||||
|
SLS.result();
|
||||||
|
}
|
||||||
|
|
||||||
|
void serialize_r(LuaSlot val) {
|
||||||
|
int tt = LS_.xtype(val);
|
||||||
|
switch (tt) {
|
||||||
|
case LUA_TNIL: {
|
||||||
|
sb_->pack_uint8(LUA_TNIL);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
case LUA_TBOOLEAN: {
|
||||||
|
if (LS_.ckboolean(val)) {
|
||||||
|
sb_->pack_uint8(LUA_PK_TRUE);
|
||||||
|
} else {
|
||||||
|
sb_->pack_uint8(LUA_PK_FALSE);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
case LUA_TLIGHTUSERDATA: {
|
||||||
|
sb_->pack_uint8(LUA_TLIGHTUSERDATA);
|
||||||
|
sb_->pack_uint64(LS_.cktoken(val).value);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
case LUA_TNUMBER: {
|
||||||
|
sb_->pack_uint8(LUA_TNUMBER);
|
||||||
|
sb_->pack_double(LS_.cknumber(val));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
case LUA_TSTRING: {
|
||||||
|
LS_.rawget(lookup_, value_to_id_, val);
|
||||||
|
if (!LS_.isnil(lookup_)) {
|
||||||
|
sb_->pack_uint8(LUA_PK_REFERENCE);
|
||||||
|
sb_->pack_uint32(LS.ckint(lookup_));
|
||||||
|
} else {
|
||||||
|
LS_.rawset(value_to_id_, val, next_id_++);
|
||||||
|
sb_->pack_uint8(LUA_TSTRING);
|
||||||
|
sb_->pack_string(LS_.ckstring(val));
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
case LUA_TTABLE: {
|
||||||
|
// LS.xtype should never return LUA_TTABLE.
|
||||||
|
error_ = "Bad xtype in serialization";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
case LUA_TFUNCTION: {
|
||||||
|
error_ = "Cannot serialize closures";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
case LUA_TUSERDATA: {
|
||||||
|
error_ = "Cannot serialize userdata";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
case LUA_TTHREAD: {
|
||||||
|
error_ = "Cannot serialize coroutines";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
case LUA_TT_GENERAL: {
|
||||||
|
LS_.rawget(lookup_, value_to_id_, val);
|
||||||
|
if (!LS_.isnil(lookup_)) {
|
||||||
|
sb_->pack_uint8(LUA_PK_REFERENCE);
|
||||||
|
sb_->pack_uint32(LS.ckint(lookup_));
|
||||||
|
} else {
|
||||||
|
LS_.rawset(value_to_id_, val, next_id_++);
|
||||||
|
serialize_table_r(val);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
case LUA_TT_REGISTRY: {
|
||||||
|
error_ = "Pointer to registry found in serialization, shouldn't happen";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
case LUA_TT_GLOBALENV: {
|
||||||
|
sb_->pack_uint8(LUA_TT_GLOBALENV);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
case LUA_TT_TANGIBLE: {
|
||||||
|
sb_->pack_uint8(LUA_TT_TANGIBLE);
|
||||||
|
sb_->pack_int64(LS_.tanid(val));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
case LUA_TT_TANGIBLEMETA: {
|
||||||
|
error_ = "Pointer to a tangible metatable found in serialization, shouldn't happen";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
case LUA_TT_CLASS: {
|
||||||
|
sb_->pack_uint8(LUA_TT_CLASS);
|
||||||
|
sb_->pack_string(LS_.classname(val));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
error_ = "Unrecognized xtype in serialization";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Serializer(LuaStack &LS0, LuaSlot val, StreamBuffer *sb, eng::string &error) :
|
||||||
|
LS_(LS0.state(), lookup_, value_to_id_), error_(error) {
|
||||||
|
next_id_ = 1;
|
||||||
|
LS_.newtable(value_to_id_);
|
||||||
|
serialize_r(val);
|
||||||
|
LS_.result();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
eng::string serialize_lua(LuaStack &LS0, LuaSlot val, StreamBuffer *sb) {
|
||||||
|
eng::string error;
|
||||||
|
Serializer sz(LS0, val, sb, error);
|
||||||
|
return error;
|
||||||
|
};
|
||||||
|
|
||||||
|
eng::string deserialize_lua(LuaStack &LS0, LuaSlot val, StreamBuffer *sb) {
|
||||||
|
eng::string error;
|
||||||
|
Deserializer dsz(LS0, val, sb, error);
|
||||||
|
if (!error_.empty()) {
|
||||||
|
LS0.set(val, LuaNil);
|
||||||
|
}
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
40
luprex/cpp/core/serializelua.hpp
Normal file
40
luprex/cpp/core/serializelua.hpp
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// This module contains routines to serialize and deserialize
|
||||||
|
// lua data structures. These routines can handle cyclic data
|
||||||
|
// structures.
|
||||||
|
//
|
||||||
|
// These routines are used for some specific difference
|
||||||
|
// transmission cases, but they're not the heart of the lua
|
||||||
|
// difference transmission system.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef SERIALIZELUA_HPP
|
||||||
|
#define SERIALIZELUA_HPP
|
||||||
|
|
||||||
|
#include "luastack.hpp"
|
||||||
|
#include "streambuffer.hpp"
|
||||||
|
|
||||||
|
// serialize_lua
|
||||||
|
//
|
||||||
|
// Serialize a value from the LuaSlot and store it in the StreamBuffer.
|
||||||
|
// On success, returns empty string.
|
||||||
|
//
|
||||||
|
// If there is an error, returns an error message. In this case, the
|
||||||
|
// streambuffer contains garbage.
|
||||||
|
//
|
||||||
|
eng::string serialize_lua(LuaStack &LS0, LuaSlot val, StreamBuffer *sb);
|
||||||
|
|
||||||
|
// deserialize_lua
|
||||||
|
//
|
||||||
|
// Deserialize a value from the StreamBuffer and store it in the LuaSlot.
|
||||||
|
// On success, returns empty string.
|
||||||
|
//
|
||||||
|
// If there is an error, returns an error message. In this case, the
|
||||||
|
// streambuffer is likely only partially consumed.
|
||||||
|
//
|
||||||
|
eng::string deserialize_lua(LuaStack &LS0, LuaSlot val, StreamBuffer *sb);
|
||||||
|
|
||||||
|
#endif // SERIALIZELUA_HPP
|
||||||
Reference in New Issue
Block a user