Created
June 11, 2025 08:28
-
-
Save SkyyySi/90c90512952fdeafdf6292b9461f6097 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
local assert = assert | |
local error = error | |
local ipairs = ipairs | |
local pairs = pairs | |
local print = print | |
local setmetatable = setmetatable | |
local tostring = tostring | |
local type = type | |
local format = string.format | |
-------------------------------------------------------------------------------- | |
---@param func_name string | |
---@param index integer | |
---@param value any | |
---@param expected_type type | |
---@return true | false | |
---@return nil | string | |
---@nodiscard | |
local function check_param_helper(func_name, index, value, expected_type) | |
local ty = type(value) | |
if ty == expected_type then | |
return true, nil | |
end | |
return false, format( | |
"bad argument #%d to '%s' (%s expected, got %s)", | |
index, | |
func_name, | |
expected_type, | |
ty | |
) | |
end | |
---@param func_name string | |
---@param params [any, type][] | |
---@return true | false | |
---@return nil | string | |
---@nodiscard | |
local function check_params(func_name, params) | |
for index, param in ipairs(params) do | |
local value = param[1] | |
local expected_type = param[2] | |
local is_ok, error_message = check_param_helper(func_name, index, value, expected_type) | |
if not is_ok then | |
return is_ok, error_message | |
end | |
end | |
return true, nil | |
end | |
-------------------------------------------------------------------------------- | |
---@alias SignalCallback fun( | |
--- self: Signal, | |
--- ...: unknown, | |
--- ) | |
---@class Signal : Signal_base | |
---@field name string | |
---@field callbacks { [SignalCallback]?: true | nil } | |
---@class Signal_base | |
local Signal_base = {} | |
Signal_base.__index = Signal_base | |
---@param self Signal | |
---@param fn SignalCallback | |
function Signal_base:connect(fn) | |
assert(check_params("connect", { | |
{ self, "table" }, | |
{ fn, "function" }, | |
})) | |
assert(self.callbacks[fn] == nil) | |
self.callbacks[fn] = true | |
end | |
---@param self Signal | |
---@param fn SignalCallback | |
function Signal_base:disconnect(fn) | |
assert(check_params("disconnect", { | |
{ self, "table" }, | |
{ fn, "function" }, | |
})) | |
assert(self.callbacks[fn] ~= nil) | |
self.callbacks[fn] = nil | |
end | |
---@param self Signal | |
---@param ... unknown | |
function Signal_base:send(...) | |
for fn, _ in pairs(self.callbacks) do | |
fn(self, ...) | |
end | |
end | |
---@class Signal_class : Signal_base | |
---@overload fun( | |
--- name: string, | |
--- callbacks?: { [SignalCallback]?: true | nil }, | |
--- ): self: Signal | |
local Signal = setmetatable({ | |
---@protected | |
__name = "Signal", | |
---@protected | |
__base = Signal_base, | |
---@protected | |
__init = function(self, name, callbacks) | |
if callbacks == nil then | |
callbacks = {} | |
end | |
assert(check_params("__init", { | |
{ self, "table" }, | |
{ name, "string" }, | |
{ callbacks, "table" }, | |
})) | |
self.name = name | |
self.callbacks = callbacks | |
end, | |
}, { | |
__index = Signal_base, | |
---@param cls Signal_class | |
---@return Signal | |
__call = function(cls, ...) | |
local self = setmetatable({}, cls.__base) --[[@as Signal]] | |
cls.__init(self, ...) | |
return self | |
end, | |
} --[[@as any]]) | |
Signal_base.__class = Signal | |
-------------------------------------------------------------------------------- | |
do | |
local my_signal = Signal("MyApp::Example") | |
my_signal:connect(function(self, value) | |
print(format( | |
"Signal %q was emitted with value: %s = %s", | |
self.name, | |
type(value), | |
tostring(value) | |
)) | |
end) | |
my_signal:send(123456) | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment