hammer/test/signal.luau
marked 2a6907434a
Some checks failed
Continous Integration / Build (push) Successful in 11s
Continous Integration / Lint (push) Successful in 9s
Continous Integration / Styling (push) Failing after 3s
Continous Integration / Unit Testing (push) Failing after 30s
Cleanup & refactor
2025-05-07 00:37:24 +02:00

96 lines
2.2 KiB
Text

-- licensed under MIT
-- @author jackdotink
-- https://github.com/red-blox/Util/blob/main/libs/Signal/Signal.luau
-- adapted to work in pure luau
type Node<T...> = {
next: Node<T...>?,
callback: (T...) -> (),
}
export type Signal<T...> = {
root: Node<T...>?,
connect: (self: Signal<T...>, Callback: (T...) -> ()) -> () -> (),
wait: (self: Signal<T...>) -> T...,
once: (self: Signal<T...>, Callback: (T...) -> ()) -> () -> (),
fire: (self: Signal<T...>, T...) -> (),
disconnect_all: (self: Signal<T...>) -> (),
}
local Signal = {}
Signal.__index = Signal
-- Extracted this function from Connect as it results in the closure
-- made in Connect using less memory because this function can be static
local function disconnect<T...>(self: Signal<T...>, Node: Node<T...>)
if self.root == Node then
self.root = Node.next
else
local Current = self.root
while Current do
if Current.next == Node then
Current.next = Node.next
break
end
Current = Current.next
end
end
end
function Signal.connect<T...>(self: Signal<T...>, Callback: (T...) -> ()): () -> ()
local node = {
next = self.root,
callback = Callback,
}
self.root = node
return function()
disconnect(self, node)
end
end
function Signal.wait<T...>(self: Signal<T...>): T...
local Thread = coroutine.running()
local Disconnect
Disconnect = self:connect(function(...)
(Disconnect :: any)()
coroutine.resume(Thread, ...)
end)
return coroutine.yield()
end
function Signal.once<T...>(self: Signal<T...>, Callback: (T...) -> ()): () -> ()
local Disconnect
Disconnect = self:connect(function(...)
(Disconnect :: any)()
Callback(...)
end)
return Disconnect
end
function Signal.fire<T...>(self: Signal<T...>, ...: T...)
local Current = self.root
while Current do
Current.callback(...)
Current = Current.next
end
end
function Signal.disconnect_all<T...>(self: Signal<T...>)
self.root = nil
end
return function<T...>(): Signal<T...>
return setmetatable({
root = nil,
}, Signal) :: any
end