-- --[[ -- lua-rubble: Rust-like struct-trait-impl system -- https://github.com/evolbug/lua-rubble -- ]] -- function struct(members) -- assert(type(members) == 'table', 'must use table for call') -- return setmetatable({ -- impls = {}, -- traits = {}, -- }, { -- __index = { -- impl = function(self, methods) -- assert(type(methods) == 'table', 'must use table for methods') -- assert(#methods == 0, 'only named members allowed') -- for k, v in pairs(methods) do -- assert(type(k) == 'string', 'name must be a string') -- assert(type(v) == 'function', 'not a method') -- assert(not self.impls[k], 'method ' .. k .. ' already defined') -- self.impls[k] = v -- end -- end, -- }, -- __call = function(self, init) -- assert(type(init) == 'table', 'must use table for init') -- assert(#init == 0, 'only named members allowed') -- for key, value in pairs(init) do -- assert(members[key], 'initializing nonexistent field ' .. key) -- assert(type(value) == members[key], -- "type mismatch for member " .. key .. ' expected:' .. members[key] .. ' got:' .. type(value)) -- end -- return setmetatable(init, { -- __index = self.impls, -- __newindex = function(self, key, value) -- assert(members[key], "setting nonexistent member " .. key) -- assert(type(value) == members[key], -- "type mismatch for member " .. key .. ' expected:' .. members[key] .. ' got:' .. type(value)) -- self[key] = value -- end, -- }) -- end, -- __newindex = function(self, key, value) -- error('struct definitions are immutable') -- end, -- }) -- end -- function trait(members) -- assert(type(members) == 'table', 'must use table for call') -- return setmetatable(members, { -- __index = { -- impl = function(self, struct) -- return function(methods) -- assert(type(methods) == 'table', 'must use table for methods') -- assert(#methods == 0, 'only named members allowed') -- for k, v in pairs(self) do -- assert(methods[k], 'must implement method ' .. k) -- assert(type(methods[k]) == 'function', 'method ' .. k .. ' not a function') -- end -- for k, v in pairs(methods) do -- assert(type(k) == 'string', 'name must be a string') -- assert(type(v) == 'function', 'not a method') -- assert(self[k], 'method not specified in trait') -- assert(not struct.impls[k], 'method ' .. k .. ' already defined') -- struct.impls[k] = v -- end -- struct.traits[self] = true -- end -- end, -- }, -- __call = function(self, init) -- assert(type(init) == 'table', 'must use table for init') -- assert(#init == 0, 'only named members allowed') -- for k, v in pairs(init) do -- assert(members[k], 'initializing nonexistent field') -- end -- return setmetatable(init, { -- __index = self.impls, -- __newindex = function(self, key, value) -- assert(members[key], "setting nonexistent member " .. key) -- assert(type(value) == members[key], "type mismatch for member") -- self[key] = value -- end, -- }) -- end, -- __newindex = function(self, key, value) -- error('trait definitions are immutable') -- end, -- }) -- end