Merge with 0.4
[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(event) -- TODO optimize index rebuilding\r
15                 local _handlers = event_map[event];\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         local function add_handler(event, handler, priority)\r
26                 local map = event_map[event];\r
27                 if map then\r
28                         map[handler] = priority or 0;\r
29                 else\r
30                         map = {[handler] = priority or 0};\r
31                         event_map[event] = map;\r
32                 end\r
33                 _rebuild_index(event);\r
34         end;\r
35         local function remove_handler(event, handler)\r
36                 local map = event_map[event];\r
37                 if map then\r
38                         map[handler] = nil;\r
39                         _rebuild_index(event);\r
40                 end\r
41         end;\r
42         local function add_plugin(plugin)\r
43                 for event, handler in pairs(plugin) do\r
44                         add_handler(event, handler);\r
45                 end\r
46         end;\r
47         local function remove_plugin(plugin)\r
48                 for event, handler in pairs(plugin) do\r
49                         remove_handler(event, handler);\r
50                 end\r
51         end;\r
52         local function _create_dispatcher(event) -- FIXME duplicate code in fire_event\r
53                 local h = handlers[event];\r
54                 if not h then h = {}; handlers[event] = h; end\r
55                 local dispatcher = function(...)\r
56                         for _, handler in ipairs(h) do\r
57                                 local ret = handler(...);\r
58                                 if ret ~= nil then return ret; end\r
59                         end\r
60                 end;\r
61                 dispatchers[event] = dispatcher;\r
62                 return dispatcher;\r
63         end;\r
64         local function get_dispatcher(event)\r
65                 return dispatchers[event] or _create_dispatcher(event);\r
66         end;\r
67         local function fire_event(event, ...) -- FIXME duplicates dispatcher code\r
68                 local h = handlers[event];\r
69                 if h then\r
70                         for _, handler in ipairs(h) do\r
71                                 local ret = handler(...);\r
72                                 if ret ~= nil then return ret; end\r
73                         end\r
74                 end\r
75         end;\r
76         local function get_named_arg_dispatcher(event, ...)\r
77                 local dispatcher = get_dispatcher(event);\r
78                 local keys = {...};\r
79                 local data = {};\r
80                 return function(...)\r
81                         for i, key in ipairs(keys) do data[key] = select(i, ...); end\r
82                         dispatcher(data);\r
83                 end;\r
84         end;\r
85         return {\r
86                 add_handler = add_handler;\r
87                 remove_handler = remove_handler;\r
88                 add_plugin = add_plugin;\r
89                 remove_plugin = remove_plugin;\r
90                 get_dispatcher = get_dispatcher;\r
91                 fire_event = fire_event;\r
92                 get_named_arg_dispatcher = get_named_arg_dispatcher;\r
93                 _dispatchers = dispatchers;\r
94                 _handlers = handlers;\r
95                 _event_map = event_map;\r
96         };\r
97 end\r
98 \r
99 return _M;\r