Jump to content

Module:User:Surjection/packer

From Wiktionary, the free dictionary


local export = {}
-- see [[Module:User:Surjection/unpacker]] for format

local common_keys = {
	"from", "remove_diacritics",
	"type", "ancestors", "wikimedia_codes", "wikipedia_article", "translit",
	"link_tr", "display_text", "entry_name", "sort_key", "dotted_dotless_i",
	"standardChars"
}

local pack_table = nil

local function trim31(s)
	local trim = #s
	while trim > 0 and s:byte(trim) == 31 do trim = trim - 1 end
	if trim < #s then return s:sub(1, trim) end
	return s
end

local function pack_table_value(v, common_keys, implicit)
	local t = type(v)
	if v == nil then
		return "\016"
	elseif t == "boolean" then
		return string.char(17, v and 1 or 0)
	elseif t == "number" then
		return "\018" .. tostring(v) .. "\031"
	elseif t == "string" then
		return "\019" .. v .. "\031"
	elseif t == "table" then
		return trim31("\020" .. pack_table(v, common_keys)) .. "\003"
	else
		error("cannot encode '" .. t .. "")
	end
end

pack_table = function (tbl, common_keys)
	local max_index = 0
	local s = ""
	
	for index, value in ipairs(tbl) do
		s = trim31(s)
		s = s .. pack_table_value(value, common_keys)
		max_index = index
	end
	for key, value in pairs(tbl) do
		if type(key) == "number" then
			if key <= 0 or key > max_index then
				s = trim31(s)
				s = string.char(2) .. tostring(key) .. pack_table_value(value, common_keys)
			end
		elseif type(key) == "string" then
			local compression = common_keys[key]
			local skey
			if compression ~= nil and compression <= 255 and #key > 2 then
				s = trim31(s)
				key = string.char(5, compression)
			elseif #key == 0 then
				s = trim31(s)
				key = string.char(2)
			end
			s = s .. key .. pack_table_value(value, common_keys)
		end
	end
	return s
end

function export.pack_rows(list, common_keys)
	local s = ""
	local common_key_indexes = {}

	for index, key in ipairs(common_keys) do
		common_key_indexes[key] = index
	end

	for top_key, top_value in pairs(list) do
		s = s .. string.char(1) .. top_key .. string.char(4) .. pack_table(top_value, common_key_indexes)
		local trim = #s
		while trim > 0 and (s:byte(trim) == 3 or s:byte(trim) == 31) do trim = trim - 1 end
		if trim < #s then s = s:sub(1, trim) end
	end

	return s .. string.char(1)
end

export.common_keys = common_keys
return export