1 local promise_methods
= {};
2 local promise_mt
= { __name
= "promise", __index
= promise_methods
};
4 local xpcall
= require
"util.xpcall".xpcall
;
6 function promise_mt
:__tostring()
7 return "promise (" .. (self
._state
or "invalid") .. ")";
10 local function is_promise(o
)
11 local mt
= getmetatable(o
);
12 return mt
== promise_mt
;
15 local function wrap_handler(f
, resolve
, reject
, default
)
19 return function (param
)
20 local ok
, ret
= xpcall(f
, debug
.traceback
, param
);
30 local function next_pending(self
, on_fulfilled
, on_rejected
, resolve
, reject
)
31 table.insert(self
._pending_on_fulfilled
, wrap_handler(on_fulfilled
, resolve
, reject
, resolve
));
32 table.insert(self
._pending_on_rejected
, wrap_handler(on_rejected
, resolve
, reject
, reject
));
35 local function next_fulfilled(promise
, on_fulfilled
, on_rejected
, resolve
, reject
) -- luacheck: ignore 212/on_rejected
36 wrap_handler(on_fulfilled
, resolve
, reject
, resolve
)(promise
.value
);
39 local function next_rejected(promise
, on_fulfilled
, on_rejected
, resolve
, reject
) -- luacheck: ignore 212/on_fulfilled
40 wrap_handler(on_rejected
, resolve
, reject
, reject
)(promise
.reason
);
43 local function promise_settle(promise
, new_state
, new_next
, cbs
, value
)
44 if promise
._state
~= "pending" then
47 promise
._state
= new_state
;
48 promise
._next
= new_next
;
49 for _
, cb
in ipairs(cbs
) do
55 local function new_resolve_functions(p
)
56 local resolved
= false;
57 local function _resolve(v
)
58 if resolved
then return; end
61 v
:next(new_resolve_functions(p
));
62 elseif promise_settle(p
, "fulfilled", next_fulfilled
, p
._pending_on_fulfilled
, v
) then
67 local function _reject(e
)
68 if resolved
then return; end
70 if promise_settle(p
, "rejected", next_rejected
, p
._pending_on_rejected
, e
) then
74 return _resolve
, _reject
;
78 local p
= setmetatable({ _state
= "pending", _next
= next_pending
, _pending_on_fulfilled
= {}, _pending_on_rejected
= {} }, promise_mt
);
80 local resolve
, reject
= new_resolve_functions(p
);
81 local ok
, ret
= pcall(f
, resolve
, reject
);
82 if not ok
and p
._state
== "pending" then
89 local function all(promises
)
90 return new(function (resolve
, reject
)
91 local count
, total
, results
= 0, #promises
, {};
93 promises
[i
]:next(function (v
)
96 if count
== total
then
104 local function race(promises
)
105 return new(function (resolve
, reject
)
106 for i
= 1, #promises
do
107 promises
[i
]:next(resolve
, reject
);
112 local function resolve(v
)
113 return new(function (_resolve
)
118 local function reject(v
)
119 return new(function (_
, _reject
)
124 local function try(f
)
125 return resolve():next(function () return f(); end);
128 function promise_methods
:next(on_fulfilled
, on_rejected
)
129 return new(function (resolve
, reject
) --luacheck: ignore 431/resolve 431/reject
130 self
:_next(on_fulfilled
, on_rejected
, resolve
, reject
);
134 function promise_methods
:catch(on_rejected
)
135 return self
:next(nil, on_rejected
);
138 function promise_methods
:finally(on_finally
)
139 local function _on_finally(value
) on_finally(); return value
; end
140 local function _on_catch_finally(err
) on_finally(); return reject(err
); end
141 return self
:next(_on_finally
, _on_catch_finally
);
151 is_promise
= is_promise
;