author | Matthew Wild <mwild1@gmail.com> |
Thu, 18 Oct 2018 12:11:50 +0100 | |
changeset 9515 | 439cf3bbe5f3 |
parent 9513 | 8ef46d09386a |
child 9516 | 4f4f9823bd1d |
permissions | -rw-r--r-- |
9459
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
1 |
local promise_methods = {}; |
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
2 |
local promise_mt = { __name = "promise", __index = promise_methods }; |
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
3 |
|
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
4 |
local function is_promise(o) |
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
5 |
local mt = getmetatable(o); |
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
6 |
return mt == promise_mt; |
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
7 |
end |
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
8 |
|
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
9 |
local function next_pending(self, on_fulfilled, on_rejected) |
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
10 |
table.insert(self._pending_on_fulfilled, on_fulfilled); |
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
11 |
table.insert(self._pending_on_rejected, on_rejected); |
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
12 |
end |
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
13 |
|
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
14 |
local function next_fulfilled(promise, on_fulfilled, on_rejected) -- luacheck: ignore 212/on_rejected |
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
15 |
on_fulfilled(promise.value); |
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
16 |
end |
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
17 |
|
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
18 |
local function next_rejected(promise, on_fulfilled, on_rejected) -- luacheck: ignore 212/on_fulfilled |
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
19 |
on_rejected(promise.reason); |
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
20 |
end |
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
21 |
|
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
22 |
local function promise_settle(promise, new_state, new_next, cbs, value) |
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
23 |
if promise._state ~= "pending" then |
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
24 |
return; |
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
25 |
end |
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
26 |
promise._state = new_state; |
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
27 |
promise._next = new_next; |
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
28 |
for _, cb in ipairs(cbs) do |
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
29 |
cb(value); |
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
30 |
end |
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
31 |
return true; |
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
32 |
end |
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
33 |
|
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
34 |
local function new_resolve_functions(p) |
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
35 |
local resolved = false; |
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
36 |
local function _resolve(v) |
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
37 |
if resolved then return; end |
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
38 |
resolved = true; |
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
39 |
if is_promise(v) then |
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
40 |
v:next(new_resolve_functions(p)); |
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
41 |
elseif promise_settle(p, "fulfilled", next_fulfilled, p._pending_on_fulfilled, v) then |
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
42 |
p.value = v; |
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
43 |
end |
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
44 |
|
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
45 |
end |
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
46 |
local function _reject(e) |
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
47 |
if resolved then return; end |
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
48 |
resolved = true; |
9515
439cf3bbe5f3
util.promise: Also support automatic resolution by returning a promise from an on_reject handler
Matthew Wild <mwild1@gmail.com>
parents:
9513
diff
changeset
|
49 |
if is_promise(e) then |
439cf3bbe5f3
util.promise: Also support automatic resolution by returning a promise from an on_reject handler
Matthew Wild <mwild1@gmail.com>
parents:
9513
diff
changeset
|
50 |
e:next(new_resolve_functions(p)); |
439cf3bbe5f3
util.promise: Also support automatic resolution by returning a promise from an on_reject handler
Matthew Wild <mwild1@gmail.com>
parents:
9513
diff
changeset
|
51 |
elseif promise_settle(p, "rejected", next_rejected, p._pending_on_rejected, e) then |
9459
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
52 |
p.reason = e; |
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
53 |
end |
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
54 |
end |
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
55 |
return _resolve, _reject; |
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
56 |
end |
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
57 |
|
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
58 |
local function new(f) |
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
59 |
local p = setmetatable({ _state = "pending", _next = next_pending, _pending_on_fulfilled = {}, _pending_on_rejected = {} }, promise_mt); |
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
60 |
if f then |
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
61 |
local resolve, reject = new_resolve_functions(p); |
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
62 |
local ok, ret = pcall(f, resolve, reject); |
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
63 |
if not ok and p._state == "pending" then |
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
64 |
reject(ret); |
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
65 |
end |
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
66 |
end |
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
67 |
return p; |
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
68 |
end |
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
69 |
|
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
70 |
local function wrap_handler(f, resolve, reject) |
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
71 |
return function (param) |
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
72 |
local ok, ret = pcall(f, param); |
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
73 |
if ok then |
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
74 |
resolve(ret); |
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
75 |
else |
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
76 |
reject(ret); |
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
77 |
end |
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
78 |
end; |
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
79 |
end |
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
80 |
|
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
81 |
function promise_methods:next(on_fulfilled, on_rejected) |
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
82 |
return new(function (resolve, reject) |
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
83 |
self:_next( |
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
84 |
on_fulfilled and wrap_handler(on_fulfilled, resolve, reject) or nil, |
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
85 |
on_rejected and wrap_handler(on_rejected, resolve, reject) or nil |
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
86 |
); |
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
87 |
end); |
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
88 |
end |
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
89 |
|
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
90 |
function promise_methods:catch(on_rejected) |
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
91 |
return self:next(nil, on_rejected); |
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
92 |
end |
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
93 |
|
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
94 |
local function all(promises) |
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
95 |
return new(function (resolve, reject) |
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
96 |
local count, total, results = 0, #promises, {}; |
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
97 |
for i = 1, total do |
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
98 |
promises[i]:next(function (v) |
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
99 |
results[i] = v; |
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
100 |
count = count + 1; |
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
101 |
if count == total then |
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
102 |
resolve(results); |
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
103 |
end |
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
104 |
end, reject); |
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
105 |
end |
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
106 |
end); |
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
107 |
end |
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
108 |
|
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
109 |
local function race(promises) |
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
110 |
return new(function (resolve, reject) |
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
111 |
for i = 1, #promises do |
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
112 |
promises[i]:next(resolve, reject); |
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
113 |
end |
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
114 |
end); |
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
115 |
end |
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
116 |
|
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
117 |
local function resolve(v) |
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
118 |
return new(function (_resolve) |
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
119 |
_resolve(v); |
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
120 |
end); |
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
121 |
end |
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
122 |
|
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
123 |
local function reject(v) |
9513
8ef46d09386a
util.promise: Fix promise.reject() to return a rejected promise, and fix buggy test for it
Matthew Wild <mwild1@gmail.com>
parents:
9459
diff
changeset
|
124 |
return new(function (_, _reject) |
9459
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
125 |
_reject(v); |
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
126 |
end); |
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
127 |
end |
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
128 |
|
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
129 |
return { |
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
130 |
new = new; |
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
131 |
resolve = resolve; |
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
132 |
reject = reject; |
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
133 |
all = all; |
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
134 |
race = race; |
d54a0e129af8
util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
135 |
} |