]> git.lizzy.rs Git - lua_async.git/blob - promises.lua
0ab61a6b20a459ca60850487d566b28f27e0a7a3
[lua_async.git] / promises.lua
1 local unpack = unpack or table.unpack
2 local PromisePrototype = {}
3
4 function PromisePrototype:__run_handler(func, ...)
5         local values = {pcall(func, ...)}
6
7         if table.remove(values, 1) then
8                 self:__resolve_raw(unpack(values))
9         else
10                 self:__reject_raw(values[1])
11         end
12 end
13
14 function PromisePrototype:__add_child(promise)
15         if self.state == "resolved" then
16                 promise:__resolve(unpack(self.values))
17         elseif self.state == "rejected" then
18                 promise:__reject(self.reason)
19         else
20                 table.insert(self.__children, promise)
21         end
22 end
23
24 function PromisePrototype:__resolve_raw(...)
25         self.state = "resolved"
26         self.values = {...}
27         self.reason = nil
28
29         for _, child in ipairs(self.__children) do
30                 child:resolve(...)
31         end
32 end
33
34 function PromisePrototype:__reject_raw(reason)
35         self.state = "rejected"
36         self.values = nil
37         self.reason = reason
38
39         local any_child = false
40
41         for _, child in ipairs(self.__children) do
42                 child:reject(reason)
43         end
44
45         assert(any_child, "Uncaught (in promise): " .. reason)
46 end
47
48 function PromisePrototype:then_(on_resolve, on_reject)
49         local promise = Promise()
50         promise.__on_resolve = on_resolve
51         promise.__on_reject = on_reject
52
53         self:__add_child(promise)
54
55         return promise
56 end
57
58 function PromisePrototype:catch(func)
59         local promise = Promise(function() end)
60         promise.__on_reject = func
61
62         self:__add_child(promise)
63
64         return promise
65 end
66
67 function PromisePrototype:resolve(...)
68         assert(self.state == "pending")
69
70         if self.__on_resolve then
71                 self:__run_handler(self.__on_resolve, ...)
72         else
73                 self:__resolve_raw(...)
74         end
75 end
76
77 function PromisePrototype:reject(reason)
78         assert(self.state == "pending")
79
80         if self.__on_reject then
81                 self:__run_handler(self.__on_reject, reason)
82         else
83                 self:__reject_raw(reason)
84         end
85 end
86
87 Promise = setmetatable({}, {
88         __call = function(_, resolver)
89                 local promise = {
90                         state = "pending",
91                         __children = {},
92                 }
93
94                 setmetatable(promise, {__index = PromisePrototype})
95
96                 if resolver then
97                         resolver(
98                                 function(...)
99                                         promise:resolve(...)
100                                 end,
101                                 function(...)
102                                         promise:reject(...)
103                                 end
104                         )
105                 end
106
107                 return promise
108         end
109 })
110
111 function Promise.resolve(...)
112         local args = {...}
113         return Promise(function(resolve)
114                 resolve(unpack(args))
115         end)
116 end