local skynet = require "skynet" local type = type local pcall = pcall local pairs = pairs local ipairs = ipairs local rawget = rawget local rawset = rawset local tostring = tostring local ssub = string.sub local sformat = string.format local dgetinfo = debug.getinfo local setmetatable = setmetatable local tinsert = table.insert local is_class -- 类模板 local class_tpls = {} local function deep_copy(src, dst) local ndst = dst or {} for key, value in pairs(src or {}) do if is_class(value) then ndst[key] = value() elseif (type(value) == "table") then ndst[key] = deep_copy(value) else ndst[key] = value end end return ndst end local function mixin_init(class, object, ...) if class.__super then mixin_init(class.__super, object, ...) end for _, mixin in ipairs(class.__mixins) do if type(mixin.__init) == "function" then mixin.__init(object, ...) end end return object end local function object_init(class, object, ...) if class.__super then object_init(class.__super, object, ...) end if type(class.__init) == "function" then class.__init(object, ...) end return object end local function object_release(class, object, ...) if type(class.__release) == "function" then class.__release(object, ...) end if class.__super then object_release(class.__super, object, ...) end end local function object_defer(class, object, ...) if type(class.__defer) == "function" then class.__defer(object, ...) end if class.__super then object_defer(class.__super, object, ...) end end local function object_default(class, object) if class.__super then object_default(class.__super, object) end local defaults = deep_copy(class.__default) for name, param in pairs(defaults) do object[name] = param[1] end end local function object_tostring(object) if type(object.tostring) == "function" then return object:tostring() end return sformat("class:%s(%s)", object.__moudle, object.__addr) end local function object_constructor(class, ...) local obj = {} object_default(class, obj) obj.__addr = ssub(tostring(obj), 7) local object = setmetatable(obj, class.__vtbl) object_init(class, object, ...) mixin_init(class, object, ...) return object end local function new(class, ...) if class.__singleton then local inst_obj = rawget(class, "__inst") if not inst_obj then inst_obj = object_constructor(class, ...) -- 定义单例方法 local inst_func = function() return inst_obj end rawset(class, "__inst", inst_obj) rawset(class, "inst", inst_func) end return inst_obj else return object_constructor(class, ...) end end local function index(class, field) return class.__vtbl[field] end local function newindex(class, field, value) class.__vtbl[field] = value end local function release(obj) object_release(obj.__class, obj) end local function defer(obj) object_defer(obj.__class, obj) end local classMT = { __call = new, __index = index, __newindex = newindex, } local function invoke(object, method, ...) local class = object.__class for _, mixin in ipairs(class.__mixins) do local mixin_method = mixin[method] if mixin_method then local ok, res = pcall(mixin_method, object, ...) if not ok then error(sformat("mixin: %s invoke '%s' failed: %s.", mixin.__moudle, method, res)) end end end end -- 返回true表示所有接口都完成 local function collect(object, method, ...) local class = object.__class for _, mixin in ipairs(class.__mixins) do local mixin_method = mixin[method] if mixin_method then local ok, res = pcall(mixin_method, object, ...) if not ok then error(sformat("mixin: %s collect '%s' failed: %s.", mixin.__moudle, method, res)) return false end if not res then skynet.error(sformat("mixin: %s collect '%s' failed: %s.", mixin.__moudle, method, res)) return false end end end return true end -- 代理一个类的所有接口,并检测接口是否实现 local function implemented(class, mixins) class.invoke = invoke class.collect = collect for _, mixin in ipairs(mixins) do -- 属性处理 for name, value in pairs(mixin.__default) do if class.__default[name] then skynet.error(sformat("the mixin default %s has repeat defined.", name)) end class.__default[name] = value local access_prefix = {"is_", "get_", "set_"} for _, prefix in pairs(access_prefix) do local access_method = prefix .. name if mixin[access_method] then tinsert(mixin.__methods, access_method) end end end for _, method in pairs(mixin.__methods) do if not mixin[method] then skynet.error(sformat("the mixin method %s hasn't implemented.", method)) mixin[method] = function() skynet.error(sformat("the mixin method %s hasn't implemented.", method)) end end if class[method] then skynet.error(sformat("the mixin method %s has repeat implemented.", method)) goto continue end -- 接口代理 class[method] = function(...) return mixin[method](...) end ::continue:: end tinsert(class.__mixins, mixin) end end local function class_constructor(class, super, ...) local info = dgetinfo(2, "S") local moudle = info.short_src local class_tpl = class_tpls[moudle] if not class_tpl then local vtbl = { __class = class, __moudle = moudle, __tostring = object_tostring, } vtbl.__gc = release vtbl.__close = defer vtbl.__index = vtbl if super then setmetatable(vtbl, { __index = super, }) end class.__vtbl = vtbl class.__super = super class.__default = {} class.__mixins = {} class_tpl = setmetatable(class, classMT) implemented(class, {...}) class_tpls[moudle] = class_tpl end return class_tpl end function class(super, ...) return class_constructor({}, super, ...) end function singleton(super, ...) return class_constructor({ __singleton = true, }, super, ...) end -- function super(class) -- return rawget(class, "__super") -- end -- function classof(object) -- return object.__class -- end is_class = function(class) return classMT == getmetatable(class) end local function is_subclass(class, super) while class do if class == super then return true end class = rawget(class, "__super") end return false end function instanceof(object, class) if not object or not class then return false end local obj_class = object.__class if obj_class then return is_subclass(obj_class, class) end return false end -- function conv_class(name) -- local runtime = sformat("local obj = %s() return obj", name) -- local ok, obj = pcall(load(runtime)) -- if ok then -- return obj -- end -- end