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
							 |