util.events: handler priorities
[prosody.git] / util / events.lua
1 \r
2 local ipairs = ipairs;\r
3 local pairs = pairs;\r
4 local t_insert = table.insert;\r
5 local t_sort = table.sort;\r
6 local select = select;\r
7 \r
8 module "events"\r
9 \r
10 function new()\r
11         local dispatchers = {};\r
12         local handlers = {};\r
13         local event_map = {};\r
14         local function _rebuild_index() -- TODO optimize index rebuilding\r
15                 for event, _handlers in pairs(event_map) do\r
16                         local index = handlers[event];\r
17                         if index then\r
18                                 for i=#index,1,-1 do index[i] = nil; end\r
19                         else index = {}; handlers[event] = index; end\r
20                         for handler in pairs(_handlers) do\r
21                                 t_insert(index, handler);\r
22                         end\r
23                         t_sort(index, function(a, b) return _handlers[a] > _handlers[b]; end);\r
24                 end\r
25         end;\r
26         local function add_handler(event, handler, priority)\r
27                 local map = event_map[event];\r
28                 if map then\r
29                         map[handler] = priority or 0;\r
30                 else\r
31                         map = {[handler] = priority or 0};\r
32                         event_map[event] = map;\r
33                 end\r
34                 _rebuild_index();\r
35         end;\r
36         local function remove_handler(event, handler)\r
37                 local map = event_map[event];\r
38                 if map then\r
39                         map[handler] = nil;\r
40                         _rebuild_index();\r
41                 end\r
42         end;\r
43         local function add_plugin(plugin)\r
44                 for event, handler in pairs(plugin) do\r
45                         add_handler(event, handler);\r
46                 end\r
47         end;\r
48         local function remove_plugin(plugin)\r
49                 for event, handler in pairs(plugin) do\r
50                         remove_handler(event, handler);\r
51                 end\r
52         end;\r
53         local function _create_dispatcher(event) -- FIXME duplicate code in fire_event\r
54                 local h = handlers[event];\r
55                 if not h then h = {}; handlers[event] = h; end\r
56                 local dispatcher = function(data)\r
57                         for _, handler in ipairs(h) do\r
58                                 local ret = handler(data);\r
59                                 if ret ~= nil then return ret; end\r
60                         end\r
61                 end;\r
62                 dispatchers[event] = dispatcher;\r
63                 return dispatcher;\r
64         end;\r
65         local function get_dispatcher(event)\r
66                 return dispatchers[event] or _create_dispatcher(event);\r
67         end;\r
68         local function fire_event(event, data) -- FIXME duplicates dispatcher code\r
69                 local h = handlers[event];\r
70                 if h then\r
71                         for _, handler in ipairs(h) do\r
72                                 local ret = handler(data);\r
73                                 if ret ~= nil then return ret; end\r
74                         end\r
75                 end\r
76         end;\r
77         local function get_named_arg_dispatcher(event, ...)\r
78                 local dispatcher = get_dispatcher(event);\r
79                 local keys = {...};\r
80                 local data = {};\r
81                 return function(...)\r
82                         for i, key in ipairs(keys) do data[key] = select(i, ...); end\r
83                         dispatcher(data);\r
84                 end;\r
85         end;\r
86         return {\r
87                 add_handler = add_handler;\r
88                 remove_handler = remove_handler;\r
89                 add_plugin = add_plugin;\r
90                 remove_plugin = remove_plugin;\r
91                 get_dispatcher = get_dispatcher;\r
92                 fire_event = fire_event;\r
93                 get_named_arg_dispatcher = get_named_arg_dispatcher;\r
94                 _dispatchers = dispatchers;\r
95                 _handlers = handlers;\r
96                 _event_map = event_map;\r
97         };\r
98 end\r
99 \r
100 return _M;\r