util/serialization.lua

1
-- Prosody IM
2
-- Copyright (C) 2008-2010 Matthew Wild
3
-- Copyright (C) 2008-2010 Waqas Hussain
4
-- 
5
-- This project is MIT/X11 licensed. Please see the
6
-- COPYING file in the source package for more information.
7
--
8
 
9
local string_rep = string.rep;
10
local type = type;
11
local tostring = tostring;
12
local t_insert = table.insert;
13
local t_concat = table.concat;
14
local error = error;
15
local pairs = pairs;
16
local next = next;
17
 
18
local loadstring = loadstring;
19
local setfenv = setfenv;
20
local pcall = pcall;
21
 
22
local debug_traceback = debug.traceback;
23
local log = require "util.logger".init("serialization");
24
module "serialization"
25
 
26
local indent = function(i)
27
	return string_rep("\t", i);
28
end
29
local function basicSerialize (o)
30
	if type(o) == "number" or type(o) == "boolean" then
31
		-- no need to check for NaN, as that's not a valid table index
32
		if o == 1/0 then return "(1/0)";
33
		elseif o == -1/0 then return "(-1/0)";
34
		else return tostring(o); end
35
	else -- assume it is a string -- FIXME make sure it's a string. throw an error otherwise.
36
		return (("%q"):format(tostring(o)):gsub("\\\n", "\\n"));
37
	end
38
end
39
local function _simplesave(o, ind, t, func)
40
	if type(o) == "number" then
41
		if o ~= o then func(t, "(0/0)");
42
		elseif o == 1/0 then func(t, "(1/0)");
43
		elseif o == -1/0 then func(t, "(-1/0)");
44
		else func(t, tostring(o)); end
45
	elseif type(o) == "string" then
46
		func(t, (("%q"):format(o):gsub("\\\n", "\\n")));
47
	elseif type(o) == "table" then
48
		if next(o) ~= nil then
49
			func(t, "{\n");
50
			for k,v in pairs(o) do
51
				func(t, indent(ind));
52
				func(t, "[");
53
				func(t, basicSerialize(k));
54
				func(t, "] = ");
55
				if ind == 0 then
56
					_simplesave(v, 0, t, func);
57
				else
58
					_simplesave(v, ind+1, t, func);
59
				end
60
				func(t, ";\n");
61
			end
62
			func(t, indent(ind-1));
63
			func(t, "}");
64
		else
65
			func(t, "{}");
66
		end
67
	elseif type(o) == "boolean" then
68
		func(t, (o and "true" or "false"));
69
	else
70
		log("error", "cannot serialize a %s: %s", type(o), debug_traceback())
71
		func(t, "nil");
72
	end
73
end
74
 
75
function append(t, o)
76
	_simplesave(o, 1, t, t.write or t_insert);
77
	return t;
78
end
79
 
80
function serialize(o)
81
	return t_concat(append({}, o));
82
end
83
 
84
function deserialize(str)
85
	if type(str) ~= "string" then return nil; end
86
	str = "return "..str;
87
	local f, err = loadstring(str, "@data");
88
	if not f then return nil, err; end
89
	setfenv(f, {});
90
	local success, ret = pcall(f);
91
	if not success then return nil, ret; end
92
	return ret;
93
end
94
 
95
return _M;