Advertisement
cduclaux

Lua Serialization

May 8th, 2014
207
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 4.43 KB | None | 0 0
  1. local write, writeIndent, writers, refCount;
  2.  
  3. persist =
  4. {
  5.     store = function (path, ...)
  6.         local file, e = io.open(path, "w");
  7.         if not file then
  8.             return error(e);
  9.         end
  10.         local n = select("#", ...);
  11.         -- Count references
  12.         local objRefCount = {}; -- Stores reference that will be exported
  13.         for i = 1, n do
  14.             refCount(objRefCount, (select(i,...)));
  15.         end;
  16.         -- Export Objects with more than one ref and assign name
  17.         -- First, create empty tables for each
  18.         local objRefNames = {};
  19.         local objRefIdx = 0;
  20.         file:write("-- Persistent Data\n");
  21.         file:write("local multiRefObjects = {\n");
  22.         for obj, count in pairs(objRefCount) do
  23.             if count > 1 then
  24.                 objRefIdx = objRefIdx + 1;
  25.                 objRefNames[obj] = objRefIdx;
  26.                 file:write("{};"); -- table objRefIdx
  27.             end;
  28.         end;
  29.         file:write("\n} -- multiRefObjects\n");
  30.         -- Then fill them (this requires all empty multiRefObjects to exist)
  31.         for obj, idx in pairs(objRefNames) do
  32.             for k, v in pairs(obj) do
  33.                 file:write("multiRefObjects["..idx.."][");
  34.                 write(file, k, 0, objRefNames);
  35.                 file:write("] = ");
  36.                 write(file, v, 0, objRefNames);
  37.                 file:write(";\n");
  38.             end;
  39.         end;
  40.         -- Create the remaining objects
  41.         for i = 1, n do
  42.             file:write("local ".."obj"..i.." = ");
  43.             write(file, (select(i,...)), 0, objRefNames);
  44.             file:write("\n");
  45.         end
  46.         -- Return them
  47.         if n > 0 then
  48.             file:write("return obj1");
  49.             for i = 2, n do
  50.                 file:write(" ,obj"..i);
  51.             end;
  52.             file:write("\n");
  53.         else
  54.             file:write("return\n");
  55.         end;
  56.         file:close();
  57.     end;
  58.  
  59.     load = function (path)
  60.         local f, e = loadfile(path);
  61.         if f then
  62.             return f();
  63.         else
  64.             return nil, e;
  65.         end;
  66.     end;
  67. }
  68.  
  69. -- Private methods
  70.  
  71. -- write thing (dispatcher)
  72. write = function (file, item, level, objRefNames)
  73.     writers[type(item)](file, item, level, objRefNames);
  74. end;
  75.  
  76. -- write indent
  77. writeIndent = function (file, level)
  78.     for i = 1, level do
  79.         file:write("\t");
  80.     end;
  81. end;
  82.  
  83. -- recursively count references
  84. refCount = function (objRefCount, item)
  85.     -- only count reference types (tables)
  86.     if type(item) == "table" then
  87.         -- Increase ref count
  88.         if objRefCount[item] then
  89.             objRefCount[item] = objRefCount[item] + 1;
  90.         else
  91.             objRefCount[item] = 1;
  92.             -- If first encounter, traverse
  93.             for k, v in pairs(item) do
  94.                 refCount(objRefCount, k);
  95.                 refCount(objRefCount, v);
  96.             end;
  97.         end;
  98.     end;
  99. end;
  100.  
  101. -- Format items for the purpose of restoring
  102. writers = {
  103.     ["nil"] = function (file, item)
  104.             file:write("nil");
  105.         end;
  106.     ["number"] = function (file, item)
  107.             file:write(tostring(item));
  108.         end;
  109.     ["string"] = function (file, item)
  110.             file:write(string.format("%q", item));
  111.         end;
  112.     ["boolean"] = function (file, item)
  113.             if item then
  114.                 file:write("true");
  115.             else
  116.                 file:write("false");
  117.             end
  118.         end;
  119.     ["table"] = function (file, item, level, objRefNames)
  120.             local refIdx = objRefNames[item];
  121.             if refIdx then
  122.                 -- Table with multiple references
  123.                 file:write("multiRefObjects["..refIdx.."]");
  124.             else
  125.                 -- Single use table
  126.                 file:write("{\n");
  127.                 for k, v in pairs(item) do
  128.                     writeIndent(file, level+1);
  129.                     file:write("[");
  130.                     write(file, k, level+1, objRefNames);
  131.                     file:write("] = ");
  132.                     write(file, v, level+1, objRefNames);
  133.                     file:write(";\n");
  134.                 end
  135.                 writeIndent(file, level);
  136.                 file:write("}");
  137.             end;
  138.         end;
  139.     ["function"] = function (file, item)
  140.             -- Does only work for "normal" functions, not those
  141.             -- with upvalues or c functions
  142.             local dInfo = debug.getinfo(item, "uS");
  143.             if dInfo.nups > 0 then
  144.                 file:write("nil --[[functions with upvalue not supported]]");
  145.             elseif dInfo.what ~= "Lua" then
  146.                 file:write("nil --[[non-lua function not supported]]");
  147.             else
  148.                 local r, s = pcall(string.dump,item);
  149.                 if r then
  150.                     file:write(string.format("loadstring(%q)", s));
  151.                 else
  152.                     file:write("nil --[[function could not be dumped]]");
  153.                 end
  154.             end
  155.         end;
  156.     ["thread"] = function (file, item)
  157.             file:write("nil --[[thread]]\n");
  158.         end;
  159.     ["userdata"] = function (file, item)
  160.             file:write("nil --[[userdata]]\n");
  161.         end;
  162. }
  163. --[[
  164. It is used like this:
  165.  
  166. t_original = {1, 2, ["a"] = "string", b = "test", {"subtable", [4] = 2}};
  167. persist.store("storage.lua", t_original);
  168. t_restored = persist.load("storage.lua");
  169. Example output (storage.lua):
  170.  
  171. -- Persistent Data
  172. return {
  173.     [1] = 1;
  174.     [2] = 2;
  175.     [3] = {
  176.         [1] = "subtable";
  177.         [4] = 2;
  178.     };
  179.     ["a"] = "string";
  180.     ["b"] = "test";
  181.    ]]--
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement