164 lines
4.3 KiB
Lua
164 lines
4.3 KiB
Lua
local Module = {}
|
||
local ReactiveWatcherMeta = {}
|
||
local ReactivePropertyMeta = {}
|
||
local reactive_watcher_stack = {}
|
||
local auto_run_watcher_mapping = {}
|
||
local triggered_watchers = {} -- 由SetProperty激活的watcher列表
|
||
|
||
local function CreateReactiveWatcher(auto_run)
|
||
local watcher = rawget(auto_run_watcher_mapping, auto_run)
|
||
if watcher == nil then
|
||
watcher = {
|
||
auto_run = auto_run,
|
||
properties = {},
|
||
}
|
||
rawset(auto_run_watcher_mapping, auto_run, watcher)
|
||
setmetatable(watcher, ReactiveWatcherMeta)
|
||
end
|
||
return watcher
|
||
end
|
||
|
||
|
||
local function PushWatcher(watcher)
|
||
table.insert(reactive_watcher_stack, watcher)
|
||
end
|
||
|
||
|
||
local function PeekWatcher()
|
||
local watcher_stack_deepth = #reactive_watcher_stack
|
||
if watcher_stack_deepth > 0 then
|
||
return reactive_watcher_stack[watcher_stack_deepth]
|
||
else
|
||
return nil
|
||
end
|
||
end
|
||
|
||
|
||
local function PopWatcher()
|
||
local watcher = PeekWatcher()
|
||
if watcher then
|
||
table.remove(reactive_watcher_stack)
|
||
end
|
||
return watcher
|
||
end
|
||
|
||
|
||
local function AddPropertyToWatcher(watcher, property, key)
|
||
local properties = watcher.properties
|
||
local keys = properties[property] or {}
|
||
keys[key] = true
|
||
properties[property] = keys
|
||
end
|
||
|
||
|
||
local function ClearAllPropertiesOfWatcher(watcher)
|
||
local properties = watcher.properties
|
||
for property, keys in pairs(properties) do
|
||
local property_watchers = property.watchers
|
||
for key, state in pairs(keys) do
|
||
if state == true then
|
||
local key_watchers = property_watchers[key]
|
||
key_watchers[watcher] = nil
|
||
end
|
||
end
|
||
end
|
||
rawset(watcher, "properties", {})
|
||
end
|
||
|
||
local function RunFunctionOfWatcher(watcher)
|
||
local auto_run = watcher.auto_run
|
||
assert(auto_run ~= nil, "can't find auto run function")
|
||
ClearAllPropertiesOfWatcher(watcher) -- 解绑所有的binding,由auto_run重新生成
|
||
PushWatcher(watcher)
|
||
auto_run()
|
||
local poped_watcher = PopWatcher()
|
||
assert(watcher == poped_watcher, "fatal")
|
||
end
|
||
|
||
|
||
local function GetReactiveProperty(property, key)
|
||
local meta = property.meta
|
||
local property_watchers = property.watchers
|
||
local current_watcher = PeekWatcher()
|
||
if current_watcher ~= nil then
|
||
local key_watchers = property_watchers[key] or {}
|
||
key_watchers[current_watcher] = true
|
||
property_watchers[key] = key_watchers
|
||
AddPropertyToWatcher(current_watcher, property, key)
|
||
end
|
||
return rawget(meta, key)
|
||
end
|
||
|
||
|
||
local function SetReactiveProperty(property, key, value)
|
||
local meta = property.meta
|
||
local property_watchers = property.watchers
|
||
rawset(meta, key, value)
|
||
local key_watchers = property_watchers[key] or {}
|
||
for watcher, state in pairs(key_watchers) do
|
||
if state == true then
|
||
triggered_watchers[watcher] = true
|
||
end
|
||
end
|
||
end
|
||
|
||
|
||
ReactiveWatcherMeta.__index = ReactiveWatcherMeta
|
||
ReactivePropertyMeta.__index = GetReactiveProperty
|
||
ReactivePropertyMeta.__newindex = SetReactiveProperty
|
||
|
||
|
||
-- 销毁Reactive Watcher
|
||
function ReactiveWatcherMeta:Destroy()
|
||
ClearAllPropertiesOfWatcher(self)
|
||
auto_run_watcher_mapping[self.auto_run] = nil
|
||
self.auto_run = nil
|
||
end
|
||
|
||
function ReactivePropertyMeta:Destroy()
|
||
local watchers = rawget(self, "watchers")
|
||
return watchers
|
||
end
|
||
|
||
|
||
-- 创建auto_run的watcher, 并运行auto_run函数
|
||
function Module.Watcher(auto_run)
|
||
local watcher = CreateReactiveWatcher(auto_run)
|
||
RunFunctionOfWatcher(watcher)
|
||
return watcher
|
||
end
|
||
|
||
function Module.ReactiveProperty(data)
|
||
local Property = {
|
||
meta = data or {},
|
||
watchers = {},
|
||
}
|
||
return setmetatable(Property, ReactivePropertyMeta)
|
||
end
|
||
|
||
function Module.RawGet(property, key)
|
||
local meta = rawget(property, "meta")
|
||
return rawget(meta, key)
|
||
end
|
||
|
||
function Module.RawSet(property, key, value)
|
||
local meta = rawget(property, "meta")
|
||
rawset(meta, key, value)
|
||
end
|
||
|
||
function Module.Process()
|
||
local limit = 64
|
||
while next(triggered_watchers) and limit > 0 do
|
||
local triggered_list = {}
|
||
for w, state in pairs(triggered_watchers) do
|
||
if state == true then table.insert(triggered_list, w) end
|
||
end
|
||
for _, w in ipairs(triggered_list) do
|
||
limit = limit - 1
|
||
triggered_watchers[w] = nil
|
||
RunFunctionOfWatcher(w)
|
||
end
|
||
end
|
||
end
|
||
|
||
return Module |