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 |