From ea436776c735608d8993776e660c4ca210eab510 Mon Sep 17 00:00:00 2001 From: cloudfreexiao <996442717qqcom@gmail.com> Date: Fri, 20 Aug 2021 21:42:58 +0800 Subject: [PATCH] =?UTF-8?q?=F0=9F=90=B3chore(=E5=BA=93):=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=20=E4=BA=8B=E4=BB=B6=20=E5=BA=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/README.md | 4 + framework/lualib/3rd/notify/dqueue.lua | 109 +++++++ framework/lualib/3rd/notify/event.lua | 431 +++++++++++++++++++++++++ framework/lualib/3rd/notify/signal.lua | 352 ++++++++++++++++++++ 4 files changed, 896 insertions(+) create mode 100755 framework/lualib/3rd/notify/dqueue.lua create mode 100755 framework/lualib/3rd/notify/event.lua create mode 100755 framework/lualib/3rd/notify/signal.lua diff --git a/docs/README.md b/docs/README.md index 0973851..b46373d 100644 --- a/docs/README.md +++ b/docs/README.md @@ -17,6 +17,10 @@ https://github.com/hellogcc/100-gdb-tips Modern Unix Command https://github.com/ibraheemdev/modern-unix +A tool for writing better scripts +https://github.com/google/zx + + https://github.com/cloudwu/skynet/issues/288 diff --git a/framework/lualib/3rd/notify/dqueue.lua b/framework/lualib/3rd/notify/dqueue.lua new file mode 100755 index 0000000..b797458 --- /dev/null +++ b/framework/lualib/3rd/notify/dqueue.lua @@ -0,0 +1,109 @@ +local setmetatable = setmetatable + +local DoubleQueue = {} + +-- Class attributes and methods goes on this table -- +local DoubleQueueObject = {} + +-- Metamethods goes on this table -- +local DoubleQueueObject_mt = { + __index = DoubleQueueObject, +} + +-- Module exported functions -- + +--- +-- Creates a new double queue. +function DoubleQueue.new() + local object = setmetatable({}, DoubleQueueObject_mt) + + -- create all the instance state data. + object.data = {} + object.data_position = {} + object.first = 1 + object.last = 0 + return object +end + +-- Private methods -- +local function refresh_first(self) + while (self.first <= self.last) do + if (self.data[self.first]) then + return true + end + self.first = self.first + 1 + end +end + +-- Public methods -- + +--- +-- Check if the queue is empty +-- @return true if it is empty, false otherwise. +function DoubleQueueObject:is_empty() + return self.first > self.last +end + +--- +-- Pushes data on the front of the queue. +-- @param data The data thas is being pushed. +function DoubleQueueObject:push_front(data) + if (self.data_position[data]) then + return + end + self.first = self.first - 1 + self.data[self.first] = data + self.data_position[data] = self.first +end + +--- +-- Pushes data on the back of the queue. +-- @param data The data thas is being pushed. +function DoubleQueueObject:push_back(data) + if (self.data_position[data]) then + return + end + self.last = self.last + 1 + self.data[self.last] = data + self.data_position[data] = self.last +end + +--- +-- Get the queue iterator. +-- Each call to the iterator function returns the next element. +-- Example: +-- +-- for data in queue:get_iterator() do +-- print("mydata: "..tostring(data)) +-- end +-- +-- @return An iterator function. +function DoubleQueueObject:get_iterator() + local first = self.first + local function iterator() + while (first <= self.last) do + local data = self.data[first] + first = first + 1 + if (data) then + return data + end + end + end + return iterator +end + +--- +-- Removes the first ocurrence of data from the queue. +-- If the data cant be found on the queue, nothing happens. +-- @param data The data that is going the be removed. +function DoubleQueueObject:remove(data) + if (not self.data_position[data]) then + return + end + self.data[self.data_position[data]] = nil + self.data_position[data] = nil + refresh_first(self) +end + +return DoubleQueue + diff --git a/framework/lualib/3rd/notify/event.lua b/framework/lualib/3rd/notify/event.lua new file mode 100755 index 0000000..ba9cea7 --- /dev/null +++ b/framework/lualib/3rd/notify/event.lua @@ -0,0 +1,431 @@ +--- https://github.com/katcipis/luanotify + + +-- This module aims to build a generic hierarchic event system. +-- The hierarchic model uses string event names to define what event are you working with. +-- +-- For example: +-- +-- * "event" -> Just a normal event. +-- * "event:subevent" -> Using the subevent feature. +-- +-- The ":" is what defines that you are using hierarchic events, +-- every ":" you put is a new hierarchic level. +-- +-- When emiting "event:subevent", everyone connected at "event" and "event:subevent" +-- is going to be notified. When emitting "event", only the ones connected at "event" are +-- going to be notified. +-- +-- Using this hierarchical structure it is easy to be notified only when a specific event happens +-- or when a whole bunch of events inside a category happens. All events can be expressed on a tree, +-- where a node is a event, and you can connect,add a pre emit, add a post emit, +-- disconnect, block, unblock, emit, on any node of the tree. +-- +-- @class module +-- @name notify.event +local setmetatable = setmetatable +local string = string +local unpack = unpack + +local Queue = require "notify.dqueue" +local separator = ":" + +-- Module exported functions +local Event = {} + +-- Class attributes and methods goes on this table -- +local EventObject = {} + +-- Metamethods goes on this table -- +local EventObject_mt = { + __index = EventObject, +} + +-- Private methods definition -- +local function new_node() + return { + handlers = Queue.new(), + pre_emits = Queue.new(), + post_emits = Queue.new(), + blocked_handlers = {}, + subevents = {}, + } +end + +local function get_nodes_names(event_name) + local nodes_names = {} + for n in string.gmatch(event_name, "[^" .. separator .. "]+") do + nodes_names[#nodes_names + 1] = n + end + return nodes_names +end + +local function get_node(self, event_name) + local events_names = get_nodes_names(event_name) + local current_node = self.events[events_names[1]] or new_node() + + self.events[events_names[1]] = current_node + for i = 2, #events_names do + local sub_node = current_node.subevents[events_names[i]] or new_node() + current_node.subevents[events_names[i]] = sub_node + current_node = sub_node + end + return current_node +end + +local function unused_event(self, event_name) + local events_names = get_nodes_names(event_name) + local current_node = self.events[events_names[1]] + + if not current_node then + return true + end + + for i = 2, #events_names do + local sub_node = current_node.subevents[events_names[i]] + if not sub_node then + return true + end + current_node = sub_node + end + + return false +end + +local function event_iterator(self, event_name) + local events_names = get_nodes_names(event_name) + local i = 2 + local current_node = self.events[events_names[1]] + + local function iterator() + if not current_node then + return + end + local ret = current_node + + if events_names[i] then + current_node = current_node.subevents[events_names[i]] + i = i + 1 + else + current_node = nil + end + + return ret + end + + return iterator +end + +local function call_pre_emits(self, event_name) + local nodes = Queue.new() + local reversed_nodes = Queue.new() + + for node in event_iterator(self, event_name) do + for pre_emit in node.pre_emits:get_iterator() do + pre_emit(event_name) + end + nodes:push_back(node) + reversed_nodes:push_front(node) + end + + return nodes, reversed_nodes +end + +local function call_post_emits(event_name, reversed_nodes) + for node in reversed_nodes:get_iterator() do + for post_emit in node.post_emits:get_iterator() do + post_emit(event_name) + end + end +end + +local function call_handlers(self, params) + for node in params.nodes:get_iterator() do + for handler in node.handlers:get_iterator() do + if (self.stopped) then + return + end + if (node.blocked_handlers[handler] == 0) then + if (params.accumulator) then + params.accumulator(handler(params.event_name, unpack(params.args))) + else + handler(params.event_name, unpack(params.args)) + end + end + end + end +end + +-- Module exported functions + +--- +-- Creates a new Event object. +-- @return The new Event object. +function Event.new() + local object = setmetatable({}, EventObject_mt) + + -- create all the instance state data. + object.stopped = false + object.events = {} + return object +end + +-- Class definition and methods -- + +--- +-- Connects a handler function on this event. +-- If any subevent is emitted, this handler will be called too. +-- @param event_name - The event name. +-- @param handler_function - The function that will be called when the event_name is emitted. +function EventObject:connect(event_name, handler_function) + local node = get_node(self, event_name) + node.handlers:push_back(handler_function) + + if not node.blocked_handlers[handler_function] then + node.blocked_handlers[handler_function] = 0 + end +end + +--- +-- Disconnects a handler function on this event. +-- @param event_name - The event name. +-- @param handler_function - The function that will be disconnected. +function EventObject:disconnect(event_name, handler_function) + if unused_event(self, event_name) then + return + end + + local node = get_node(self, event_name) + node.handlers:remove(handler_function) + node.blocked_handlers[handler_function] = nil +end + +--- +-- Does not execute the given handler function when the give event is emitted until it is unblocked. +-- It can be called several times for the same handler function. +-- +-- Example: +-- +-- local Event = require "notify.event" +-- local event = Event.new() + +-- local function handler1(arg) +-- print(arg) +-- end +-- +-- event:connect("mouse", handler1) +-- event:emit("mouse", "example") -- example gets printed. +-- +-- event:block("mouse", handler1); +-- event:emit("mouse", "example") -- nothing gets printed. +-- +-- +-- @param event_name - The event name. +-- @param handler_function - The handler function that will be blocked. +function EventObject:block(event_name, handler_function) + if unused_event(self, event_name) then + return + end + + local node = get_node(self, event_name) + local block = node.blocked_handlers[handler_function] + if block then + node.blocked_handlers[handler_function] = block + 1 + end +end + +--- +-- Unblocks the handler function from the given event. +-- The calls to unblock must match the calls to block. +-- +-- Example: +-- +-- local Event = require "notify.event" +-- local event = Event.new() +-- +-- local function handler1(arg) +-- print(arg) +-- end +-- +-- event:connect("mouse", handler1) +-- event:emit("mouse", "example") -- example gets printed. +-- +-- event:block("mouse", handler1); +-- event:emit("mouse", "example") -- nothing gets printed. +-- +-- event:block("mouse", handler1); +-- event:emit("mouse", "example") -- nothing gets printed. +-- +-- event:unblock("mouse", handler1); +-- event:emit("mouse", "example") -- nothing gets printed. +-- event:unblock("mouse", handler1); +-- event:emit("mouse", "example") -- example gets printed. +-- +-- +-- @param event_name - The event name. +-- @param handler_function - The handler function that will be unblocked. +function EventObject:unblock(event_name, handler_function) + if unused_event(self, event_name) then + return + end + + local node = get_node(self, event_name) + if node.blocked_handlers[handler_function] and node.blocked_handlers[handler_function] > 0 then + + node.blocked_handlers[handler_function] = node.blocked_handlers[handler_function] - 1 + end +end + +--- +-- Emits an event and all handler functions connected to it will be called. +-- Emiting the event "event1::event2::event3" will call the handlers connected +-- on the following events, on this order: +-- * event1 +-- * event1:event2 +-- * event1:event2:event3 +-- +-- @param event_name - The event name. +-- @param ... - A optional list of parameters, they will be repassed to the handler functions connected to this event. +function EventObject:emit(event_name, ...) + self.stopped = false + local nodes, reversed_nodes = call_pre_emits(self, event_name) + call_handlers(self, { + event_name = event_name, + nodes = nodes, + args = {...}, + }) + call_post_emits(event_name, reversed_nodes) +end + +--- +-- Typical emission discards handlers return values completely. +-- This is most often what you need: just inform the world about something. +-- However, sometimes you need a way to get feedback. +-- For instance, you may want to ask: “is this value acceptable ?” +-- This is what accumulators are for. Accumulators are specified to events at emission time. +-- They can combine, alter or discard handlers return values, post-process them or even stop emission. +-- Since a handler can return multiple values, accumulators can receive multiple args too. +-- Following Lua flexible style we give the user the freedom to do whatever he wants with accumulators. +-- If you are using the hierarchic event system the behaviour of handlers calling is similar to the emit function. +-- @param event_name - The event name. +-- @param accumulator - Function that will receive handlers results or a table to accumulate +-- all the handlers returned values. +-- @param ... - A optional list of parameters, they will be repassed to the handler +-- functions connected to this signal. +function EventObject:emit_with_accumulator(event_name, accumulator, ...) + self.stopped = false + local nodes, reversed_nodes = call_pre_emits(self, event_name) + call_handlers(self, { + event_name = event_name, + nodes = nodes, + accumulator = accumulator, + args = {...}, + }) + call_post_emits(event_name, reversed_nodes) +end + +--- +-- Adds a pre_emit func, pre_emit functions can't be blocked, only added or removed. +-- They can't have their return collected by accumulators, they will not receive any data +-- passed on the emission and they are always called before ANY handler is called. +-- This is useful when you want to perform some global task before handling an event, +-- like opening a socket that the handlers might need to use or a opening a database. +-- pre_emit functions can make sure everything is ok before handling an event, reducing +-- the need to do this check_ups inside the handler functions itself (sometimes multiple times). +-- They are called on a queue (FIFO) policy based on the order they added. +-- When using hierarchy, pre_emission happen top-bottom. For example, with a mouse::button1 event, +-- first the pre_emit functions on mouse will be called, then mouse::button1 post_emit functions will be called. +-- @param event_name - The event name. +-- @param pre_emit_func - The pre_emit function. +function EventObject:add_pre_emit(event_name, pre_emit_func) + get_node(self, event_name).pre_emits:push_back(pre_emit_func) +end + +--- +-- Removes a pre-emit func from the given event. +-- @param event_name - The event name. +-- @param pre_emit_func - The pre_emit function. +function EventObject:remove_pre_emit(event_name, pre_emit_func) + if unused_event(self, event_name) then + return + end + get_node(self, event_name).pre_emits:remove(pre_emit_func) +end + +--- +-- Adds a post_emit function, post_emit functions can't be blocked, only added or removed, +-- they can't have their return collected by accumulators, they will not receive any data passed +-- on the emission and they are always called after ALL handlers where called. +-- This is useful when you want to perform some global task after handling an event, +-- like closing a socket or a database that the handlers might need to use or do some cleanup. +-- post_emit functions can make sure everything is released after handling an event, reducing the need +-- to do this check_ups inside some handler function, since some resources can be shared by multiple handlers. +-- They are called on a stack (LIFO) policy based on the order they added. When using hierarchy, +-- post_emission happen bottom-top. For example, with a mouse::button1 event, first the post_emit +-- functions on mouse::button1 will be called, then mouse post_emit functions will be called. +-- @param event_name - The event name. +-- @param post_emit_func - The post_emit function. +function EventObject:add_post_emit(event_name, post_emit_func) + get_node(self, event_name).post_emits:push_front(post_emit_func) +end + +--- +-- Removes a post-emit func from the given event. +-- @param event_name - The event name. +-- @param post_emit_func - The post_emit function. +function EventObject:remove_post_emit(event_name, post_emit_func) + if unused_event(self, event_name) then + return + end + get_node(self, event_name).post_emits:remove(post_emit_func) +end + +--- +-- Has effect only during a emission and will stop only this particular emission of the event. +-- Usually called inside a pre-emit (when a condition fail) or on any handler. +-- +-- Example: +-- +-- local Event = require "notify.event" +-- local event = Event.new() +-- +-- function handler1() +-- print("handler1") +-- event.stop(); +-- end +-- +-- function handler2() +-- print("2") +-- end +-- +-- event:connect("mouse", handler1) +-- event:connect("mouse::click", handler2) +-- +-- event:emit("mouse::click") --handler2 never gets printed because handler1 always stops the emission +-- +function EventObject:stop() + self.stopped = true +end + +--- +-- Removes all pre/post-emits and handlers from the given event_name. +-- If no name is given all pre/post-emits and handlers will be removed. +-- @param event_name - The name of the event that will be cleared, or nil to clear all events. +function EventObject:clear(event_name) + if (not event_name) then + self.events = {} + return + end +end + +-- Public functions -- +local global_event = Event.new() + +--- +-- Always returns the same Event instance, this way is easy to share the same Event object across different modules. +-- @return An EventObject instance. +function Event.get_global_event() + return global_event +end + +return Event diff --git a/framework/lualib/3rd/notify/signal.lua b/framework/lualib/3rd/notify/signal.lua new file mode 100755 index 0000000..41b5257 --- /dev/null +++ b/framework/lualib/3rd/notify/signal.lua @@ -0,0 +1,352 @@ +--- +-- Signal object implementation. +-- @class module +-- @name notify.signal +local setmetatable = setmetatable +local Queue = require "notify.dqueue" + +local Signal = {} + +-- Class attributes and methods goes on this table -- +local SignalObject = {} + +-- Metamethods goes on this table -- +local SignalObject_mt = { + __index = SignalObject, +} + +-- Class definition and methods -- + +--- +-- Disconnects a handler function from this signal, the function will no longer be called. +-- Example: +-- +-- local signal = require "notify.signal" +-- local s = signal.new() +-- +-- function handler(arg) +-- print(arg) +-- end +-- +-- s:connect(handler) +-- s:emit("example") -- example gets printed +-- s:disconnect(handler) +-- s:emit("example") -- nothing gets printed +-- +-- @param handler_function – The function that will be disconnected. +function SignalObject:disconnect(handler_function) + self.handlers:remove(handler_function) + self.handlers_block[handler_function] = nil +end + +--- +-- Connects a handler function on this signal, all handlers connected will be called +-- when the signal is emitted with a FIFO behaviour (The first connected will be the first called). +-- Example: +-- local signal = require "notify.signal" +-- +-- function handler1(arg) +-- print(arg.."1") +-- end +-- function handler2(arg) +-- print(arg.."2") +-- end +-- +-- local s = signal.new() +-- s:connect(handler1) +-- s:connect(handler2) +-- s:emit("example") -- example1 gets printed before example2. +-- +-- @param handler_function – The function that will be called when this signal is emitted. +function SignalObject:connect(handler_function) + if (not self.handlers_block[handler_function]) then + self.handlers_block[handler_function] = 0 + self.handlers:push_back(handler_function) + end +end + +--- +-- Does not execute the given handler function when the signal is emitted until it is unblocked. +-- It can be called several times for the same handler function. +-- Example: +-- +-- local signal = require "notify.signal" +-- local s = signal.new() +-- +-- function handler(arg) +-- print(arg) +-- end +-- +-- s:connect(handler) +-- s:emit("example") -- example gets printed +-- +-- s:block(handler) +-- s:emit("example") -- nothing gets printed +-- +-- @param handler_function – The handler function that will be blocked. +function SignalObject:block(handler_function) + if (self.handlers_block[handler_function]) then + self.handlers_block[handler_function] = self.handlers_block[handler_function] + 1 + end +end + +--- +-- Unblocks the given handler function, this handler function will be executed on +-- the order it was previously connected, and it will only be unblocked when +-- the calls to unblock are equal to the calls to block. +-- Example: +-- +-- local signal = require "notify.signal" +-- local s = signal.new() +-- function handler(arg) +-- print(arg) +-- end +-- s:connect(handler) +-- s:emit("example") -- example gets printed +-- s:block(handler) +-- s:emit("example") -- nothing gets printed +-- s:block(handler) +-- s:emit("example") -- nothing gets printed +-- s:unblock(handler) +-- s:emit("example") -- nothing gets printed +-- s:unblock(handler) +-- s:emit("example") -- example gets printed +-- +-- @param handler_function – The handler function that will be unblocked. +function SignalObject:unblock(handler_function) + if (self.handlers_block[handler_function]) then + if (self.handlers_block[handler_function] > 0) then + self.handlers_block[handler_function] = self.handlers_block[handler_function] - 1 + end + end +end + +--- +-- Emits a signal calling the handler functions connected to this signal passing the given args. +-- +-- local signal = require "notify.signal" +-- local s = signal.new() +-- function handler1(arg1, arg2) +-- print(arg1) +-- print(arg2) +-- end +-- function handler2(arg) +-- print(arg) +-- end + +-- s:connect(handler1) +-- s:connect(handler2) +-- s:emit("example") -- a nil will get printed because only one argument was passed +-- s:emit("example1", "example2") -- No nil will get printed. +-- s:emit() -- Only nils will get printed because no argument was passed. +-- +-- @param … – A optional list of parameters, they will be repassed to the handler functions connected to this signal. +function SignalObject:emit(...) + self.signal_stopped = false + + for set_up in self.pre_emit_funcs:get_iterator() do + set_up() + end + + for handler in self.handlers:get_iterator() do + if (self.signal_stopped) then + break + end + if (self.handlers_block[handler] == 0) then + handler(...) + end + end + + for tear_down in self.post_emit_funcs:get_iterator() do + tear_down() + end +end + +--- +-- Typical signal emission discards handler return values completely. +-- This is most often what you need: just inform the world about something. +-- However, sometimes you need a way to get feedback. For instance, +-- you may want to ask: “is this value acceptable ?” +-- This is what accumulators are for. Accumulators are specified to signals at emission time. +-- They can combine, alter or discard handler return values, post-process them or even stop emission. +-- Since a handler can return multiple values, accumulators can receive multiple args too, following +-- Lua flexible style user has the freedom to do whatever he wants with accumulators. +-- +-- local signal = require "notify.signal" +-- local s = signal.new() +-- +-- function handler1(arg) +-- return arg * 2 +-- end +-- +-- function handler2(arg) +-- return arg * 3 +-- end +-- +-- local result = {} +-- function accum(arg) +-- result[#result+1] = arg +-- end +-- +-- s:connect(handler1) +-- s:connect(handler2) +-- +-- s:emit_with_accumulator(accum, 2) +-- +-- for k,v in ipairs(result) do -- print 4, 6 +-- print(v) +-- end +-- +-- @param accumulator – Function that will accumulate handlers results. +-- @param … – A optional list of parameters, they will be repassed to the handler functions connected to this signal. +function SignalObject:emit_with_accumulator(accumulator, ...) + self.signal_stopped = false; + + for set_up in self.pre_emit_funcs:get_iterator() do + set_up() + end + + for handler in self.handlers:get_iterator() do + if (self.signal_stopped) then + break + end + if (self.handlers_block[handler] == 0) then + accumulator(handler(...)) + end + end + + for tear_down in self.post_emit_funcs:get_iterator() do + tear_down() + end +end + +--- +-- Adds a pre_emit func, pre_emit functions cant be blocked, only added or removed, +-- they cannot have their return collected by accumulators, will not receive any data passed +-- on the emission and they are always called before ANY handler is called. +-- This is useful when you want to perform some global task before handling an event, +-- like opening a socket that the handlers might need to use or a database, pre_emit functions +-- can make sure everything is ok before handling an event, reducing the need to do this check_ups +-- inside the handler function. They are called on a queue (FIFO) policy based on the order they added. +-- +-- local signal = require "notify.signal" +-- local s = signal.new() +-- +-- function handler1() +-- print(1) +-- end +-- +-- function handler2() +-- print(2) +-- end +-- +-- function pre_emit() +-- print("0") +-- end +-- +-- s:connect(handler1) +-- s:connect(handler2) +-- s:emit() -- 1 and 2 printed. +-- s:add_pre_emit(pre_emit) +-- s:emit() -- 0,1 and 2 are printed. +-- +-- @param pre_emit_func – The pre_emit function. +function SignalObject:add_pre_emit(pre_emit_func) + self.pre_emit_funcs:push_back(pre_emit_func) +end + +--- +-- Removes the pre_emit function +-- @param pre_emit_func – The pre_emit function. +function SignalObject:remove_pre_emit(pre_emit_func) + self.pre_emit_funcs:remove(pre_emit_func) +end + +--- +-- Adds a post_emit function, post_emit functions cant be blocked, only added or removed, +-- they cannot have their return collected by accumulators, they will not receive any data +-- passed on the emission and they are always called after ALL handlers where called. +-- This is useful when you want to perform some global task after handling an event, +-- like closing a socket that the handlers might need to use or a database or do some cleanup. +-- post_emit functions can make sure everything is released after handling an event, +-- reducing the need to do this check_ups inside some handler function, since some resources +-- can be shared by multiple handlers. They are called on a stack (LIFO) policy based on the order they added. +-- Example: +-- +-- local signal = require "notify.signal" +-- local s = signal.new() +-- +-- function handler1() +-- print(1) +-- end +-- +-- function handler2() +-- print(2) +-- end +-- +-- function post_emit() +-- print("3") +-- end +-- +-- s:connect(handler1) +-- s:connect(handler2) +-- s:emit() -- 1 and 2 printed. +-- s:add_post_emit(post_emit) +-- s:emit() -- 1, 2 and 3 are printed. +-- +-- @param post_emit_func – The post_emit function. +function SignalObject:add_post_emit(post_emit_func) + self.post_emit_funcs:push_front(post_emit_func) +end + +--- +-- Removes the post_emit function +-- @param post_emit_func – The post_emit function. +function SignalObject:remove_post_emit(post_emit_func) + self.post_emit_funcs:remove(post_emit_func) +end + +--- +-- Stops the current emission, if there is any handler left to be called by the signal it wont be called. +-- Example: +-- +-- local signal = require "notify.signal" +-- local s = signal.new() +-- +-- local function handler1() +-- print("hanlder1") +-- signal:stop() +-- end +-- +-- local function handler2() +-- print("hanlder2") +-- end +-- +-- s:connect(handler1) +-- s:connect(handler2) +-- s:emit() -- handler2 never gets printed because handler1 always stops the emission +-- +function SignalObject:stop() + self.signal_stopped = true +end + +-- Signal module exported functions -- + +--- +-- Creates a new SignalObject. +function Signal.new() + local object = {} + -- set the metatable of the new object as the SignalObject_mt table (inherits SignalObject). + setmetatable(object, SignalObject_mt) + + -- create all the instance state data. + object.handlers_block = {} + object.handlers = Queue.new() + object.pre_emit_funcs = Queue.new() + object.post_emit_funcs = Queue.new() + object.signal_stopped = false + return object +end + +return Signal +