Files
aux-addon-ClassicAPI/control.lua
T

142 lines
3.0 KiB
Lua

module 'aux'
local T = require 'T'
local event_frame = CreateFrame('Frame', 'AuxThreadingFrame')
local listeners, threads = T.acquire(), T.acquire()
local listener_counts = T.acquire()
local listeners_dirty
local thread_id
function M.thread_id() return thread_id end
function handle.LOAD()
event_frame:SetScript('OnEvent', EVENT)
end
local function cleanup_listeners()
if not listeners_dirty then return end
for id, listener in listeners do
if listener.killed then
listeners[id] = nil
end
end
listeners_dirty = nil
end
function EVENT()
for _, listener in listeners do
if not listener.killed and event == listener.event then
listener.cb(listener.kill)
end
end
cleanup_listeners()
end
do
function UPDATE()
cleanup_listeners()
for id, thread in threads do
if thread.killed or not thread.k then
threads[id] = nil
if not next(threads) then -- Disable threading task so it doesn't consume resources doing nothing
event_frame:SetScript('OnUpdate', nil)
end
else
local k = thread.k
thread.k = nil
thread_id = id
k()
thread_id = nil
end
end
end
end
do
local id = 0
function unique_id()
id = id + 1
return id
end
end
function M.kill_listener(listener_id)
local listener = listeners[listener_id]
if listener and not listener.killed then
listener.killed = true
listeners_dirty = true
local listener_event = listener.event
listener_counts[listener_event] = (listener_counts[listener_event] or 1) - 1
if listener_counts[listener_event] <= 0 then
listener_counts[listener_event] = nil
event_frame:UnregisterEvent(listener_event)
end
end
end
function M.kill_thread(thread_id)
local thread = threads[thread_id]
if thread then
thread.killed = true
end
end
function M.event_listener(event, cb)
local listener_id = unique_id()
listeners[listener_id] = T.map(
'event', event,
'cb', cb,
'kill', T.vararg-function(arg) if getn(arg) == 0 or arg[1] then kill_listener(listener_id) end end
)
if not listener_counts[event] then
event_frame:RegisterEvent(event)
listener_counts[event] = 1
else
listener_counts[event] = listener_counts[event] + 1
end
return listener_id
end
function M.on_next_event(event, callback)
event_listener(event, function(kill) callback(); kill() end)
end
do
local mt = {
__call = function(self)
T.temp(self)
return self.f(unpack(self))
end,
}
M.thread = T.vararg-function(arg)
T.static(arg)
arg.f = tremove(arg, 1)
local thread_id = unique_id()
threads[thread_id] = T.map('k', setmetatable(arg, mt))
if event_frame:GetScript("OnUpdate") == nil then -- Spin up threading if it was turned off
event_frame:SetScript('OnUpdate', UPDATE)
end
return thread_id
end
M.wait = T.vararg-function(arg)
T.static(arg)
arg.f = tremove(arg, 1)
threads[thread_id].k = setmetatable(arg, mt)
end
end
M.when = T.vararg-function(arg)
local c = tremove(arg, 1)
local k = tremove(arg, 1)
if c() then
return k(unpack(arg))
else
return wait(when, c, k, unpack(arg))
end
end