-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathstruct.lua
More file actions
95 lines (80 loc) · 2.66 KB
/
struct.lua
File metadata and controls
95 lines (80 loc) · 2.66 KB
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
-- typecheck returns nothing, works because tables operate via pointers.
-- typecheck DOES NOT need to deal with defaults
local function typecheck (t, types)
assert(type(t) == "table",
string.format("bad argument #1 to 'typecheck' (table expected, got %s)", type(t))
)
for key, wantType in pairs(types) do
-- if the expected type is a table call ourselves on it.
if type(wantType) == "table" then
typecheck(t[key], wantType)
else
-- make sure it is the type we expect
assert(type(t[key]) == wantType,
string.format("key '%s' want type '%s' got type '%s'", key, wantType, type(t[key]))
)
end
end
-- check for unwanted fields being filled,
-- ignore functions because methods are okay.
for key, val in pairs(t) do
-- if it is not a function then go boom
if types[key] == nil and type(val) ~= "function" then
error(string.format("key '%s' is not part of the struct", key))
end
end
end
-- allTypes returns every type in a 'key = key; value = type' table.
local function allTypes (t)
local types = {}
for key, val in pairs(t) do
if type(val) == "table" then
types[key] = allTypes(val)
else
types[key] = type(val)
end
end
return types
end
-- returns an updated table
function setDefaults (t, defaults)
-- if t is nil then set it to an empty table.
t = t or {}
-- iterate over the defaults and set them if they are not supplied
for key, default in pairs(defaults) do
-- if the default is a table then run it on the subtable in t.
if type(default) == "table" then
t[key] = setDefaults(t[key], default)
else
-- otherwise just set it to the default if t[key] is nil
if t[key] == nil then
t[key] = default
end
end
end
return t
end
-- struct creates a new struct data structure from a table,
-- it is type safe.
local function struct (t)
assert(type(t) == "table",
string.format("bad argument #1 to 'struct' (table expected, got %s)", type(t))
)
local types = allTypes(t)
-- return a metatable that typechecks the values it gets, but
-- sets defaults when they are nil.
local mt = {}
-- calling the table returns the table with defaults (after typechecking it)
mt.__call = function (self, o)
-- Using setDefaults because when i use __index it does not set
-- defaults correctly if o is {}, only when o is nil.
-- (maybe applying __index recursively?)
o = setDefaults(o, self)
-- typecheck the values (ignores extra functions)
typecheck(o, types)
-- return the new instance
return o
end
return setmetatable(t, mt)
end
return struct