local count_impls = 0
local trait_type_mt = {
__index = {
declare_method = function(self, methodname)
if self.methods[methodname] then
error("trait " .. self.name .. " method " .. methodname .. " is already declared")
end
self.methods[methodname] = true
end,
implement_on = function(self, ty, methods)
count_impls = count_impls + 1
if type(ty) ~= "table" then
error("trying to implement on something that isn't a type")
end
if self.impls[ty] then
error("trait " .. self.name .. " already implemented on type " .. tostring(ty))
end
local implemented_methods = {}
for k in pairs(self.methods) do
implemented_methods[k] = methods[k]
or error(
"missing method " .. k .. " implementing trait " .. self.name .. " on type " .. tostring(ty)
)
end
self.impls[ty] = implemented_methods
end,
get = function(self, ty)
return self.impls[ty] or nil end,
},
}
local function declare_trait(name)
return setmetatable({ name = name, methods = {}, impls = {} }, trait_type_mt)
end
local pretty_print = declare_trait("pretty_print")
pretty_print:declare_method("pretty_print")
pretty_print:declare_method("default_print")
local diff = declare_trait("diff")
diff:declare_method("diff")
local value_name = declare_trait("value_name")
value_name:declare_method("value_name")
local freeze = declare_trait("freeze")
freeze:declare_method("freeze")
local order = declare_trait("order")
order:declare_method("compare")
local glsl_print = declare_trait("glsl_print")
glsl_print:declare_method("glsl_print")
glsl_print:declare_method("glsl_check")
return {
declare_trait = declare_trait,
pretty_print = pretty_print,
diff = diff,
value_name = value_name,
freeze = freeze,
order = order,
glsl_print = glsl_print,
}