summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorruki <[email protected]>2018-12-05 22:49:24 +0800
committerruki <[email protected]>2018-12-05 10:56:25 +0800
commitb7e17b562985e6854ddcf67c5524da9c5d045875 (patch)
treec048e2309c86cebe234b9d42dc6db830f707c036
parent824a61bb67014f10313b2f872b039fc47b51e5db (diff)
serialize table and function
-rw-r--r--xmake/core/base/io.lua103
-rw-r--r--xmake/core/base/table.lua91
2 files changed, 92 insertions, 102 deletions
diff --git a/xmake/core/base/io.lua b/xmake/core/base/io.lua
index a07d127ea..66859f3fc 100644
--- a/xmake/core/base/io.lua
+++ b/xmake/core/base/io.lua
@@ -70,107 +70,21 @@ function _file:close()
return self._FILE:close()
end
--- save object with the level
-function _file:_save(object, level)
-
- -- save string
- if type(object) == "string" then
- self:printf("%q", object)
- -- save boolean
- elseif type(object) == "boolean" then
- self:write(tostring(object))
- -- save number
- elseif type(object) == "number" then
- self:write(object)
- -- save table
- elseif type(object) == "table" then
-
- -- save head
- self:write("\n")
- for l = 1, level do
- self:write(" ")
- end
- self:write("{\n")
-
- -- save body
- local i = 0
- for k, v in pairs(object) do
-
- -- save spaces and separator
- for l = 1, level do
- self:write(" ")
- end
-
- self:write(utils.ifelse(i == 0, " ", ", "))
-
- -- save key
- if type(k) == "string" then
- self:write(string.format("[%q]", k), " = ")
- end
-
- -- save value
- if not self:_save(v, level + 1) then
- return false
- end
-
- -- save newline
- self:write("\n")
- i = i + 1
- end
-
- -- save tail
- for l = 1, level do
- self:write(" ")
- end
- self:write("}\n")
- else
- -- error
- utils.error("invalid object type: %s", type(object))
- return false
- end
-
- -- ok
- return true
-end
-
-- save object
function _file:save(object)
- return self:_save(object, 0)
+ local str, errors = table.makestr(object, false, true)
+ if str then
+ self:write(str)
+ end
+ return str, errors
end
-- load object
function _file:load()
-
- -- check
- assert(self)
-
- -- load data
- local result = nil
- local errors = nil
local data = self:read("*all")
if data and type(data) == "string" then
-
- -- load script
- local script, errs = loadstring("return " .. data)
- if script then
-
- -- load object
- local ok, object = pcall(script)
- if ok and object then
- result = object
- elseif object then
- -- error
- errors = object
- else
- -- error
- errors = string.format("load %s failed!", filepath)
- end
- -- errors
- else errors = errs end
+ return table.loadstr(data)
end
-
- -- ok?
- return result, errors
end
-- read all data from file
@@ -275,10 +189,11 @@ function io.save(filepath, object)
end
-- save object to file
- if not file:save(object) then
+ local ok, errors = file:save(object)
+ if not ok then
-- error
file:close()
- return false, string.format("save %s failed!", filepath)
+ return false, string.format("save %s failed, %s!", filepath, errors)
end
-- close file
diff --git a/xmake/core/base/table.lua b/xmake/core/base/table.lua
index 3de4be277..6b600ad1e 100644
--- a/xmake/core/base/table.lua
+++ b/xmake/core/base/table.lua
@@ -26,10 +26,12 @@
local table = table or {}
-- make string with the level
-function table._makestr(self, deflate, level)
- if type(self) == "string" or type(self) == "boolean" or type(self) == "number" then
+function table._makestr(self, deflate, serialize, level)
+ if type(self) == "string" then
+ return serialize and string.format("%q", self) or self
+ elseif type(self) == "boolean" or type(self) == "number" then
return tostring(self)
- elseif type(self) == "table" and (getmetatable(self) or {}).__tostring then
+ elseif not serialize and type(self) == "table" and (getmetatable(self) or {}).__tostring then
return tostring(self)
elseif type(self) == "table" then
@@ -64,13 +66,20 @@ function table._makestr(self, deflate, level)
-- make key = value
if type(k) == "string" then
+ if serialize then
+ k = string.format("[%q]", k)
+ end
if deflate then
s = s .. k .. "="
else
s = s .. k .. " = "
end
end
- s = s .. table._makestr(v, deflate, level + 1)
+ local substr, errors = table._makestr(v, deflate, serialize, level + 1)
+ if substr == nil then
+ return nil, errors
+ end
+ s = s .. substr
if not deflate then
s = s .. "\n"
@@ -86,6 +95,10 @@ function table._makestr(self, deflate, level)
end
s = s .. "}"
return s
+ elseif serialize and type(self) == "function" then
+ return string.format("%q", string.dump(self))
+ elseif serialize then
+ return nil, "cannot serialize object: " .. type(self)
elseif self ~= nil then
return "<" .. tostring(self) .. ">"
else
@@ -93,6 +106,24 @@ function table._makestr(self, deflate, level)
end
end
+-- load table from string in table
+function table._loadstr(self)
+ -- only load luajit function data: e.g. "\27LJ\2\0\6=stdin"
+ if type(self) == "string" and self:startswith("\27LJ") then
+ return loadstring(self)
+ elseif type(self) == "table" then
+ for k, v in pairs(self) do
+ local value, errors = table._loadstr(v)
+ if value ~= nil then
+ self[k] = value
+ else
+ return nil, errors
+ end
+ end
+ end
+ return self
+end
+
-- clear the table
function table.clear(self)
for k in next, self do
@@ -259,13 +290,57 @@ function table.is_dictionary(dict)
end
-- dump table
-function table.dump(self, deflate)
- io.write(table.makestr(self, deflate))
+function table.dump(self, deflate, serialize)
+ local str = table.makestr(self, deflate, serialize)
+ if str then
+ io.write(str)
+ end
end
-- make string from the given table
-function table.makestr(self, deflate)
- return table._makestr(self, deflate, 0)
+--
+-- @param deflate deflate empty characters
+-- @param serialize make string which can be deserialized, we can use table.loadstr to load it
+--
+-- @return string, errors
+--
+function table.makestr(self, deflate, serialize)
+ return table._makestr(self, deflate, serialize, 0)
+end
+
+-- load table from the serialized string
+--
+-- @param str the serialized string
+--
+-- @return table, errors
+--
+function table.loadstr(str)
+
+ -- load table as script
+ local result = nil
+ local script, errors = loadstring("return " .. str)
+ if script then
+
+ -- load object
+ local ok, object = pcall(script)
+ if ok and object then
+ result = object
+ elseif object then
+ -- error
+ errors = object
+ else
+ -- error
+ errors = string.format("cannot deserialize string: %s", str)
+ end
+ end
+
+ -- load function from string in table
+ if result then
+ result, errors = table._loadstr(result)
+ end
+
+ -- ok?
+ return result, errors
end
-- unwrap object if be only one