Files
BusyRabbit/Content/Lua/Core/Reactive.lua

164 lines
4.3 KiB
Lua
Raw Normal View History

2025-07-09 01:08:35 +08:00
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