-- 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 = { next: Node?, callback: (T...) -> (), } export type Signal = { root: Node?, connect: (self: Signal, Callback: (T...) -> ()) -> () -> (), wait: (self: Signal) -> T..., once: (self: Signal, Callback: (T...) -> ()) -> () -> (), fire: (self: Signal, T...) -> (), disconnect_all: (self: Signal) -> (), } 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(self: Signal, Node: Node) 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(self: Signal, Callback: (T...) -> ()): () -> () local node = { next = self.root, callback = Callback, } self.root = node return function() disconnect(self, node) end end function Signal.wait(self: Signal): T... local Thread = coroutine.running() local Disconnect Disconnect = self:connect(function(...) (Disconnect :: any)() coroutine.resume(Thread, ...) end) return coroutine.yield() end function Signal.once(self: Signal, Callback: (T...) -> ()): () -> () local Disconnect Disconnect = self:connect(function(...) (Disconnect :: any)() Callback(...) end) return Disconnect end function Signal.fire(self: Signal, ...: T...) local Current = self.root while Current do Current.callback(...) Current = Current.next end end function Signal.disconnect_all(self: Signal) self.root = nil end return function(): Signal return setmetatable({ root = nil, }, Signal) :: any end