Update event to remove middleclass, using defold-event as a base

This commit is contained in:
Insality 2024-08-29 09:51:09 +03:00
parent ba1ab07e0d
commit 0aeb0b3fea

View File

@ -8,10 +8,16 @@
-- @module DruidEvent -- @module DruidEvent
-- @alias druid.event -- @alias druid.event
local class = require("druid.system.middleclass") local M = {}
M.COUNTER = 0
local DruidEvent = class("druid.event") -- Forward declaration
local EVENT_METATABLE
-- Local versions
local pcall = pcall
local tinsert = table.insert
local tremove = table.remove
--- DruidEvent constructor --- DruidEvent constructor
-- @tparam DruidEvent self @{DruidEvent} -- @tparam DruidEvent self @{DruidEvent}
@ -20,19 +26,44 @@ local DruidEvent = class("druid.event")
-- local Event = require("druid.event") -- local Event = require("druid.event")
-- ... -- ...
-- local event = Event(initial_callback) -- local event = Event(initial_callback)
function DruidEvent.initialize(self, initial_callback) function M.create(callback, callback_context)
self._callbacks = nil -- initialize later local instance = setmetatable({}, EVENT_METATABLE)
if initial_callback then if callback then
self:subscribe(initial_callback) instance:subscribe(callback, callback_context)
end end
M.COUNTER = M.COUNTER + 1
return instance
end
--- Check is event subscribed.
-- @tparam DruidEvent self @{DruidEvent}
-- @tparam function callback Callback itself
-- @tparam any|nil callback_context Additional context as first param to callback call
-- @treturn boolean, number|nil @Is event subscribed, return index of callback in event as second param
function M.is_subscribed(self, callback, callback_context)
if #self == 0 then
return false, nil
end
for index = 1, #self do
local cb = self[index]
if cb[1] == callback and cb[2] == callback_context then
return true, index
end
end
return false, nil
end end
--- Subscribe callback on event --- Subscribe callback on event
-- @tparam DruidEvent self @{DruidEvent} -- @tparam DruidEvent self @{DruidEvent}
-- @tparam function callback Callback itself -- @tparam function callback Callback itself
-- @tparam any|nil context Additional context as first param to callback call, usually it's self -- @tparam any|nil callback_context Additional context as first param to callback call, usually it's self
-- @treturn boolean True if callback was subscribed
-- @usage -- @usage
-- local function on_long_callback(self) -- local function on_long_callback(self)
-- print("Long click!") -- print("Long click!")
@ -40,41 +71,39 @@ end
-- ... -- ...
-- local button = self.druid:new_button("button", callback) -- local button = self.druid:new_button("button", callback)
-- button.on_long_click:subscribe(on_long_callback, self) -- button.on_long_click:subscribe(on_long_callback, self)
function DruidEvent.subscribe(self, callback, context) function M.subscribe(self, callback, callback_context)
assert(type(self) == "table", "You should subscribe to event with : syntax") assert(type(self) == "table", "You should subscribe to event with : syntax")
assert(type(callback) == "function", "Callback should be function") assert(callback, "A function must be passed to subscribe to an event")
self._callbacks = self._callbacks or {} if self:is_subscribed(callback, callback_context) then
table.insert(self._callbacks, { return false
callback = callback, end
context = context
})
return callback tinsert(self, { callback, callback_context })
return true
end end
--- Unsubscribe callback on event --- Unsubscribe callback on event
-- @tparam DruidEvent self @{DruidEvent} -- @tparam DruidEvent self @{DruidEvent}
-- @tparam function callback Callback itself -- @tparam function callback Callback itself
-- @tparam any|nil context Additional context as first param to callback call -- @tparam any|nil callback_context Additional context as first param to callback call
-- @usage -- @usage
-- local function on_long_callback(self) -- local function on_long_callback(self)
-- print("Long click!") -- print("Long click!")
-- end -- end
-- ... -- ...
-- button.on_long_click:unsubscribe(on_long_callback, self) -- button.on_long_click:unsubscribe(on_long_callback, self)
function DruidEvent.unsubscribe(self, callback, context) function M.unsubscribe(self, callback, callback_context)
if not self._callbacks then assert(callback, "A function must be passed to subscribe to an event")
return
local _, event_index = self:is_subscribed(callback, callback_context)
if not event_index then
return false
end end
for index, callback_info in ipairs(self._callbacks) do tremove(self, event_index --[[@as number]])
if callback_info.callback == callback and callback_info.context == context then return true
table.remove(self._callbacks, index)
return
end
end
end end
@ -83,11 +112,18 @@ end
-- @treturn boolean True if event have handlers -- @treturn boolean True if event have handlers
-- @usage -- @usage
-- local is_long_click_handler_exists = button.on_long_click:is_exist() -- local is_long_click_handler_exists = button.on_long_click:is_exist()
function DruidEvent.is_exist(self) function M.is_exist(self)
if not self._callbacks then return #self > 0
return false
end end
return #self._callbacks > 0
--- Return true, if event not have handler
--- @tparam DruidEvent self @{DruidEvent}
--- @treturn boolean True if event not have handlers
--- @usage
--- local is_long_click_handler_not_exists = button.on_long_click:is_empty()
function M:is_empty()
return #self == 0
end end
@ -95,8 +131,10 @@ end
-- @tparam DruidEvent self @{DruidEvent} -- @tparam DruidEvent self @{DruidEvent}
-- @usage -- @usage
-- button.on_long_click:clear() -- button.on_long_click:clear()
function DruidEvent.clear(self) function M.clear(self)
self._callbacks = nil for index = #self, 1, -1 do
self[index] = nil
end
end end
@ -108,19 +146,60 @@ end
-- ... -- ...
-- local event = Event() -- local event = Event()
-- event:trigger("Param1", "Param2") -- event:trigger("Param1", "Param2")
function DruidEvent.trigger(self, ...) function M.trigger(self, ...)
if not self._callbacks then if #self == 0 then
return false return
end end
for _, callback_info in ipairs(self._callbacks) do local result = nil
if callback_info.context then
callback_info.callback(callback_info.context, ...) local call_callback = self.call_callback
for index = 1, #self do
result = call_callback(self, self[index], ...)
end
return result
end
-- @tparam table callback Callback data {function, context}
-- @tparam any ... All event params
-- @treturn any Result of the callback
-- @local
function M:call_callback(callback, ...)
local event_callback = callback[1]
local event_callback_context = callback[2]
-- Call callback
local ok, result_or_error
if event_callback_context then
ok, result_or_error = pcall(event_callback, event_callback_context, ...)
else else
callback_info.callback(...) ok, result_or_error = pcall(event_callback, ...)
end
end
end end
-- Handle errors
if not ok then
local caller_info = debug.getinfo(2)
pprint("An error occurred during event processing", {
trigger = caller_info.short_src .. ":" .. caller_info.currentline,
error = result_or_error,
})
pprint("Traceback", debug.traceback())
return nil
end
return DruidEvent return result_or_error
end
-- Construct event metatable
EVENT_METATABLE = {
__index = M,
__call = M.trigger,
}
return setmetatable(M, {
__call = function(_, callback)
return M.create(callback)
end,
})