aboutsummaryrefslogtreecommitdiff
path: root/src/util.lua
blob: f74953a5ba8452dbdf4fffbec2235c6e6b40206c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
--[[
Various helpful functions
]]
local util = {}
function util.cartesian(...)
	-- cartesian(tbl1, tbl2, tbl3, ...)
	-- for each table, returns a permutation of key, value in tbl1, tbl2, ect.
	local args = {...}
	return coroutine.wrap(function()
		local cursors = {} -- cursors[1], cursors[3], ect. are the keys
		for k,v in ipairs(args) do
			local a,b = next(v,nil)
			cursors[(k*2) - 1] = a
			cursors[(k*2)] = b
		end
		coroutine.yield(unpack(cursors))
		local any_left = true
		while any_left do
			while next(args[#args],cursors[#cursors - 1]) do
				local a,b = next(args[#args],cursors[#cursors - 1])
				cursors[#cursors - 1] = a
				cursors[#cursors] = b
				coroutine.yield(unpack(cursors))
			end
			any_left = false
			for i = #args, 1, -1 do
				if next(args[i],cursors[(i*2)-1]) then
					cursors[(i*2)-1], cursors[i*2] = next(args[i],cursors[(i*2)-1])
					for j = i+1, #args do
						cursors[(j*2)-1], cursors[j*2] = next(args[j],nil)
					end
					coroutine.yield(unpack(cursors))
					any_left = true
					break
				end
			end
		end
	end)
end

-- Override tostring to display more info about the table
local old_tostring = tostring
local numtabs = 0
local printed_tables = {}
local function tostring_helper(el)
        assert(type(el) == "table", "Tried to call helper with something that was not a table, it was a " .. type(el))
        local mt = getmetatable(el)
        if mt and mt.__tostring then
                return mt.__tostring(el)
        elseif printed_tables[el] == true then
                return old_tostring(el)
        else
                printed_tables[el] = true
                numtabs = numtabs + 1
                local strbuilder = {"{"}
                for k,v in pairs(el) do
                        local key,value
                        if type(k) == "table" then
                                key = tostring_helper(k)
                        else
                                key = old_tostring(k)
                        end
                        if type(v) == "table" then
                                value = tostring_helper(v)
                        else
                                value = old_tostring(v)
                        end
                        strbuilder[#strbuilder + 1] = string.format("%s%s : %s", string.rep("\t",numtabs), key, value)
                end
                strbuilder[#strbuilder + 1] = string.rep("\t",numtabs - 1) .. "}"
                numtabs = numtabs - 1
                return table.concat(strbuilder,"\n")
        end

end
function tostring(el)
        printed_tables = {}
        if type(el) == "table" then
                return tostring_helper(el)
        end
        return old_tostring(el)
end

function util.reverse(tbl, val)
	val = val or true
	local ret = {}
	for _,v in ipairs(tbl) do
		ret[v] = val
	end
	return ret
end

function util.typecheck(tbl, ...)
	local args = {...}
	assert(#args % 2 == 0,"Typecheck should have an odd number of arguments, found " .. tostring(#args + 1) .. ".")
	for i = 1, #args, 2 do
		assert(args[i] and type(args[i]) == "string", "Cannot check a field of type " .. type(args[i]) .. " at position " .. tostring(i + 1) .. ".")
		assert(tbl[args[i]], "Failed to find a field: " .. args[i])
		assert(args[i+1] and type(args[i + 1]) == "string", "Cannot check for a type " .. type(args[i + 1]) .. " at position " .. tostring(i + 2) .. ".")
		assert(type(tbl[args[i]]) == args[i+1], "Expected a " .. args[i+1] .. " at position " .. tostring(i+2) .. " but found a " .. type(tbl[args[i]]))
	end
	return true
end

function util.peer_to_code(str)
	-- Turn peerjs peer ids into shorter strings
	-- Example: 0dbbe67a-5358-4ea2-910a-195754b556a7
	-- = 16 bytes
	local buffer = am.buffer(16)
	local view = buffer:view("ubyte")
	local i = 0
	for byte in str:gmatch("%x%x") do
		local n = tonumber(byte,16)
		view[(i % 16) + 1] = n
		i = i + 1
	end
	local encoded = am.base64_encode(buffer)
	return encoded:gsub("[/+]",{["/"] = "-",["+"] = "_"}):sub(1,22) -- chop the last 2 glyphs, assume 16 bytes
end

function util.code_to_peer(str)
	local padded = str:gsub("[_-]",{["-"] = "/", ["_"] = "+"}) .. "=="
	local buffer = am.base64_decode(padded)
	local view = buffer:view("ubyte")
	local dashes = {4,2,2,2,6}
	local builder = {}
	local i = 1
	while #dashes > 0 do
		local nbytes = table.remove(dashes,1)
		for _ = 1, nbytes do
			table.insert(builder, string.format("%02x",view[i]))
			i = i + 1
		end
		if #dashes > 0 then
			table.insert(builder,"-")
		end
	end
	ret = table.concat(builder)
	return ret
end

return util