quad/src/store.lua
2023-01-04 02:48:08 +09:00

208 lines
4.8 KiB
Lua

local module = {};
--[[
this feature allows get object without making some created callback and local var
but, it can't allows mulit id and object
this feature should be upgraded
]]
local wrap = coroutine.wrap;
local insert = table.insert;
local remove = table.remove;
local gmatch = string.gmatch;
local gsub = string.gsub;
local function catch(...)
local passed,err = pcall(...);
if not passed then
warn ("[QUAD] Error occured while operating async task\n" .. tostring(err));
end
end
local week = {__mode = "v"};
---@param shared quad_export
---@return quad_module_store
function module.init(shared)
---@class quad_module_store
local new = {__type = "quad_module_store"};
local items = shared.items;
-- id space (array of object)
local objectListClass = {__type = "quad_objectlist"};
function objectListClass:each(func)
local index = 1;
for i,v in pairs(self) do
wrap(catch)(func,index,v);
index = index + 1;
end
end
function objectListClass:eachSync(func)
local index = 1;
for _,v in pairs(self) do
local ret = func(index,v);
index = index + 1;
if ret then
break;
end
end
end
function objectListClass:remove(indexOrItem)
local thisType = type(indexOrItem);
if thisType == "number" then
remove(self,indexOrItem);
else
for i,v in pairs(self) do
if v == indexOrItem then
remove(self,i);
break;
end
end
end
end
function objectListClass:isEmpty()
if next(self) then return true; end
return false;
end
function objectListClass.__new()
return setmetatable({},objectListClass);
end
function objectListClass:__newIndex(key,value) -- props setter
self:each(function (this)
this[key] = value;
end);
end
objectListClass.__mode = "kv"; -- week link for gc
objectListClass.__index = objectListClass;
-- get object array with id (objSpace)
function new.getObjects(id)
local list = items[id];
if list then return list; end
list = objectListClass.__new(id);
items[id] = list;
return list;
end
-- get first object with id (not array)
function new.getObject(id)
local item = items[id];
return item and item[next(item)];
end
--TODO: if item is exist already, ignore this call
-- adding object with id
function new.addObject(ids,object)
for id in gmatch(ids,"[^,]+") do -- split by ,
-- remove trailing, heading spaces
id = gsub(gsub(id,"^ +","")," +$","");
local array = items[id];
if not array then
array = objectListClass.__new();
items[id] = array;
end
insert(array, object);
end
end
local registerClass = {
__type = "quad_register";
register = function (s,efunc)
local self = s.store;
local events = self.__evt;
for key in s.key:gmatch("[^,]+") do
key = key:gsub("^ +",""):gsub(" +$","");
local event = events[key];
if not event then
event = setmetatable({},week);
events[key] = event;
end
insert(event,efunc);
end
end;
with = function (s,efunc)
return setmetatable({wfunc = efunc},{__index = s});
end;
default = function (s,value)
return setmetatable({dvalue = value},{__index = s});
end;
tween = function (s,value)
return setmetatable({tvalue = value},{__index = s});
end;
---@deprecated
from = function (s,value)
warn "[QUAD] register:from() is deprecated. You can use register:add(t:table|function) instead";
return setmetatable({fvalue = value},{__index = s});
end;
add = function (s,value)
return setmetatable({avalue = value},{__index = s});
end;
};
registerClass.__index = registerClass;
-- bindable store object
local store = {__type = "quad_store"};
local storeIdSpace = {};
function store:__index(key)
local this = self.__self[key];
if this ~= nil then
return this;
end
return store[key];
end
function store:__newindex(key,value)
self.__self[key] = value;
local event = self.__evt[key];
if event then
for _,v in pairs(event) do -- NO ipairs here
wrap(catch)(v,store,value,key);
end
end
end
function store:__call(key,func)
local last = self.__self[key];
if last and type(last) == "table" and getmetatable(last) == registerClass then
return last;
end
local register = self.__reg[key];
if not register then
register = setmetatable({
key = key;
store = self;
t = "reg";
},registerClass);
self.__reg[key] = register;
end
if func then
register.register(func);
end
return register;
end
function store:default(key,value)
local old = self[key];
if old == nil then
self[key] = value;
return;
end
end
function new.new(self,id)
if id then
local old = storeIdSpace[id];
if old then
return old;
end
end
local this = setmetatable(
{__self = self or {},__evt = {},__reg = setmetatable({},week)},store
);
if id then
storeIdSpace[id] = this;
end
return this;
end
function new.getStore(id)
return storeIdSpace[id] or new.new({},id);
end
return new;
end
return module;