Skip to content

Commit

Permalink
Clean up defer module and split DeferMethod to its own method
Browse files Browse the repository at this point in the history
  • Loading branch information
p3lim committed Jul 22, 2024
1 parent b6031e6 commit e0c938e
Showing 1 changed file with 49 additions and 45 deletions.
94 changes: 49 additions & 45 deletions modules/defer.lua
Original file line number Diff line number Diff line change
@@ -1,74 +1,78 @@
local _, addon = ...

local queue = {}
local function iterateQueue()
local function iterate()
for _, info in next, queue do
if info.callback then
info.callback(unpack(info.args))
local successful, ret = pcall(info.callback, unpack(info.args))
if not successful then
error(ret)
end
elseif info.object then
info.object[info.method](unpack(info.args))
local successful, ret = pcall(info.object[info.method], info.object, unpack(info.args))
if not successful then
error(ret)
end
end
end

table.wipe(queue)
return true -- unregister itself
return true -- unregister event
end

local function deferFunction(callback, ...)
local function defer(info)
table.insert(queue, info)

if not addon:IsEventRegistered('PLAYER_REGEN_ENABLED', iterate) then
addon:RegisterEvent('PLAYER_REGEN_ENABLED', iterate)
end
end


--[[ namespace:Defer(_callback_[, _..._])
Defers a function `callback` (with optional arguments) until after combat ends.
Callback can be the global name of a function.
Triggers immediately if player is not in combat.
--]]
function addon:Defer(callback, ...)
if type(callback) == 'string' then
callback = _G[callback]
end

addon:ArgCheck(callback, 1, 'function')

if InCombatLockdown() then
table.insert(queue, {
defer({
callback = callback,
args = {...},
})

if not addon:IsEventRegistered('PLAYER_REGEN_ENABLED', iterateQueue) then
addon:RegisterEvent('PLAYER_REGEN_ENABLED', iterateQueue)
end
else
callback(...)
local successful, ret = pcall(callback, ...)
if not successful then
error(ret)
end
end
end

local function deferGlobalFunction(func, ...)
deferFunction(_G[func], ...)
end
--[[ namespace:DeferMethod(_object_, _method_[, _..._])
Defers a `method` on `object` (with optional arguments) until after combat ends.
Triggers immediately if player is not in combat.
--]]
function addon:DeferMethod(object, method, ...)
addon:ArgCheck(object, 1, 'table')
addon:ArgCheck(method, 2, 'string')
addon:ArgCheck(object[method], 2, 'function')

local function deferMethod(object, method, ...)
if InCombatLockdown() then
table.insert(queue, {
defer({
object = object,
method = method,
args = {...},
})

if not addon:IsEventRegistered('PLAYER_REGEN_ENABLED', iterateQueue) then
addon:RegisterEvent('PLAYER_REGEN_ENABLED', iterateQueue)
end
else
object[method](...)
end
end

--[[ namespace:Defer(_callback_[, _..._])
Defers a function `callback` (with optional arguments) until after combat ends.
Immediately triggers if player is not in combat.
--]]
--[[ namespace:Defer(_object_, _method_[, _..._])
Defers a method `method` on `object` (with optional arguments) until after combat ends.
Immediately triggers if player is not in combat.
--]]
function addon:Defer(...)
if type(select(1, ...)) == 'table' then
assert(type(select(2, ...)) == 'string', 'arg2 must be the name of a method')
assert(type(select(1, ...)[select(2, ...)]) == 'function', 'arg2 must be the name of a method')
deferMethod(...)
elseif type(select(1, ...)) == 'function' then
assert(type(select(1, ...)) == 'function', 'arg1 must be a function')
deferFunction(...)
elseif type(select(1, ...)) == 'string' and type(_G[select(1, ...)]) == 'function' then
assert(type(_G[select(1, ...)]) == 'function', 'arg1 must be a function')
deferGlobalFunction(...)
else
error('Invalid arguments passed to Defer')
local successful, ret = pcall(object[method], object, ...)
if not successful then
error(ret)
end
end
end

0 comments on commit e0c938e

Please sign in to comment.