Lua: Serializer


Actually text has limited relation to that thing on right side

Today I wrote a serializer function for Lua. A brief research has shown that not too many people know what this should do in first place. So, to theory:
For example, you have this table definition:
local o = {
	1, 2, 3,
	one = 1,
	['Lua is'] = 'cool',
	[true] = true,
	{ 'this', 'is', 'a', 'table' }
}
At the time of 'compilation' (translation to VM bytecode) it is translated into non-textual representation that you can't tell a lot about, and probably should not worry about.
However, what if you want to get your modified table back, as text? That's where a bit of puzzle appears, since there isn't a standard routine to do that. And also where scope of using this function starts.
So, if you were to do serialize(o, true) after above code, you would get the following string (highlighted as code for easier comparison):
{
    1,
    2,
    3,
    {
        "this",
        "is",
        "a",
        "table",
    },
    one = 1,
    [true] = true,
    ["Lua is"] = "cool",
}
And if you want things to stay compact, you can set 'multiline' parameter to 'false', making function call serialize(o, false) and leading to this result:
{ 1, 2, 3, { "this", "is", "a", "table", }, one = 1, [true] = true, ["Lua is"] = "cool", }
As you can see, in both cases output code is functionally identical to input, despite of multiple index and value types used.
The most common usage of this function would be saving-loading the game - why would you need to organize complex save-load systems (where these are not needed), when you can simply 'dump' entire value with a single function call, and load it with dofile()?
Other common use is debugging - change properties while game is running, and get new code to be saved.
-- serialize ~ by YellowAfterlife
-- Converts value back into according Lua presentation
-- Accepts strings, numbers, boolean values, and tables.
-- Table values are serialized recursively, so tables linking to themselves or
-- linking to other tables in "circles". Table indexes can be numbers, strings,
-- and boolean values.
function serialize(object, multiline, depth, name)
	depth = depth or 0
	if multiline == nil then multiline = true end
	local padding = string.rep('    ', depth) -- can use '\t' if printing to file
	local r = padding -- result string
	if name then -- should start from name
		r = r .. (
			-- enclose in brackets if not string or not a valid identifier
			-- thanks to Boolsheet from #love@irc.oftc.net for string pattern
			(type(name) ~= 'string' or name:find('^([%a_][%w_]*)$') == nil)
			and ('[' .. (
				(type(name) == 'string')
				and string.format('%q', name)
				or tostring(name))
				.. ']')
			or tostring(name)) .. ' = '
	end
	if type(object) == 'table' then
		r = r .. '{' .. (multiline and '\n' or ' ')
		local length = 0
		for i, v in ipairs(object) do
			r = r .. serialize(v, multiline, multiline and (depth + 1) or 0) .. ','
				.. (multiline and '\n' or ' ')
			length = i
		end
		for i, v in pairs(object) do
			local itype = type(i) -- convert type into something easier to compare:
			itype =(itype == 'number') and 1
				or (itype == 'string') and 2
				or (itype == 'boolean') and 3
				or error('Serialize: Unsupported index type "' .. itype .. '"')
			local skip = -- detect if item should be skipped
				((itype == 1) and ((i % 1) == 0) and (i >= 1) and (i <= length)) -- ipairs part
				or ((itype == 2) and (string.sub(i, 1, 1) == '_')) -- prefixed string
			if not skip then
				r = r .. serialize(v, multiline, multiline and (depth + 1) or 0, i) .. ','
					.. (multiline and '\n' or ' ')
			end
		end
		r = r .. (multiline and padding or '') .. '}'
	elseif type(object) == 'string' then
		r = r .. string.format('%q', object)
	elseif type(object) == 'number' or type(object) == 'boolean' then
		r = r .. tostring(object)
	else
		error('Unserializeable value "' .. tostring(object) .. '"')
	end
	return r
end

Related posts:

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.