util/promise.lua
author Matthew Wild <mwild1@gmail.com>
Mon, 20 Feb 2023 18:10:15 +0000
branch0.12
changeset 12898 0598d822614f
parent 11951 073e53b72792
child 12593 39ae08180c81
permissions -rw-r--r--
mod_websocket: Fire pre-session-close event (fixes #1800) This event was added in a7c183bb4e64 and is required to make mod_smacks know that a session was intentionally closed and shouldn't be hibernated (see fcea4d9e7502). Because this was missing from mod_websocket's session.close(), mod_smacks would always attempt to hibernate websocket sessions even if they closed cleanly. That mod_websocket has its own copy of session.close() is something to fix another day (probably not in the stable branch). So for now this commit makes the minimal change to get things working again. Thanks to Damian and the Jitsi team for reporting.
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
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
9565
acf74ad0b795 Many things: switch from hacky multi-arg xpcall implementations to a standard util.xpcall
Matthew Wild <mwild1@gmail.com>
parents: 9562
diff changeset
     4
local xpcall = require "util.xpcall".xpcall;
11488
a0120e935442 util.promise: Add join() convenience method
Matthew Wild <mwild1@gmail.com>
parents: 11487
diff changeset
     5
local unpack = table.unpack or unpack; --luacheck: ignore 113
9565
acf74ad0b795 Many things: switch from hacky multi-arg xpcall implementations to a standard util.xpcall
Matthew Wild <mwild1@gmail.com>
parents: 9562
diff changeset
     6
9518
2571c65b972f util.promise: Add a string representation
Kim Alvefur <zash@zash.se>
parents: 9517
diff changeset
     7
function promise_mt:__tostring()
2571c65b972f util.promise: Add a string representation
Kim Alvefur <zash@zash.se>
parents: 9517
diff changeset
     8
	return  "promise (" .. (self._state or "invalid") .. ")";
2571c65b972f util.promise: Add a string representation
Kim Alvefur <zash@zash.se>
parents: 9517
diff changeset
     9
end
2571c65b972f util.promise: Add a string representation
Kim Alvefur <zash@zash.se>
parents: 9517
diff changeset
    10
9459
d54a0e129af8 util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    11
local function is_promise(o)
d54a0e129af8 util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    12
	local mt = getmetatable(o);
d54a0e129af8 util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    13
	return mt == promise_mt;
d54a0e129af8 util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    14
end
d54a0e129af8 util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    15
9552
800c274928bf util.promise: Ensure chained promises always receive a value/rejection even if an intermediate promise has no handlers
Matthew Wild <mwild1@gmail.com>
parents: 9551
diff changeset
    16
local function wrap_handler(f, resolve, reject, default)
800c274928bf util.promise: Ensure chained promises always receive a value/rejection even if an intermediate promise has no handlers
Matthew Wild <mwild1@gmail.com>
parents: 9551
diff changeset
    17
	if not f then
800c274928bf util.promise: Ensure chained promises always receive a value/rejection even if an intermediate promise has no handlers
Matthew Wild <mwild1@gmail.com>
parents: 9551
diff changeset
    18
		return default;
800c274928bf util.promise: Ensure chained promises always receive a value/rejection even if an intermediate promise has no handlers
Matthew Wild <mwild1@gmail.com>
parents: 9551
diff changeset
    19
	end
800c274928bf util.promise: Ensure chained promises always receive a value/rejection even if an intermediate promise has no handlers
Matthew Wild <mwild1@gmail.com>
parents: 9551
diff changeset
    20
	return function (param)
9562
7c65e3f38e6e util.promise: Switch from pcall to xpcall to get tracebacks on exceptions
Matthew Wild <mwild1@gmail.com>
parents: 9561
diff changeset
    21
		local ok, ret = xpcall(f, debug.traceback, param);
9552
800c274928bf util.promise: Ensure chained promises always receive a value/rejection even if an intermediate promise has no handlers
Matthew Wild <mwild1@gmail.com>
parents: 9551
diff changeset
    22
		if ok then
800c274928bf util.promise: Ensure chained promises always receive a value/rejection even if an intermediate promise has no handlers
Matthew Wild <mwild1@gmail.com>
parents: 9551
diff changeset
    23
			resolve(ret);
800c274928bf util.promise: Ensure chained promises always receive a value/rejection even if an intermediate promise has no handlers
Matthew Wild <mwild1@gmail.com>
parents: 9551
diff changeset
    24
		else
800c274928bf util.promise: Ensure chained promises always receive a value/rejection even if an intermediate promise has no handlers
Matthew Wild <mwild1@gmail.com>
parents: 9551
diff changeset
    25
			reject(ret);
800c274928bf util.promise: Ensure chained promises always receive a value/rejection even if an intermediate promise has no handlers
Matthew Wild <mwild1@gmail.com>
parents: 9551
diff changeset
    26
		end
800c274928bf util.promise: Ensure chained promises always receive a value/rejection even if an intermediate promise has no handlers
Matthew Wild <mwild1@gmail.com>
parents: 9551
diff changeset
    27
		return true;
800c274928bf util.promise: Ensure chained promises always receive a value/rejection even if an intermediate promise has no handlers
Matthew Wild <mwild1@gmail.com>
parents: 9551
diff changeset
    28
	end;
9459
d54a0e129af8 util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    29
end
d54a0e129af8 util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    30
9552
800c274928bf util.promise: Ensure chained promises always receive a value/rejection even if an intermediate promise has no handlers
Matthew Wild <mwild1@gmail.com>
parents: 9551
diff changeset
    31
local function next_pending(self, on_fulfilled, on_rejected, resolve, reject)
800c274928bf util.promise: Ensure chained promises always receive a value/rejection even if an intermediate promise has no handlers
Matthew Wild <mwild1@gmail.com>
parents: 9551
diff changeset
    32
	table.insert(self._pending_on_fulfilled, wrap_handler(on_fulfilled, resolve, reject, resolve));
800c274928bf util.promise: Ensure chained promises always receive a value/rejection even if an intermediate promise has no handlers
Matthew Wild <mwild1@gmail.com>
parents: 9551
diff changeset
    33
	table.insert(self._pending_on_rejected, wrap_handler(on_rejected, resolve, reject, reject));
9459
d54a0e129af8 util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    34
end
d54a0e129af8 util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    35
9552
800c274928bf util.promise: Ensure chained promises always receive a value/rejection even if an intermediate promise has no handlers
Matthew Wild <mwild1@gmail.com>
parents: 9551
diff changeset
    36
local function next_fulfilled(promise, on_fulfilled, on_rejected, resolve, reject) -- luacheck: ignore 212/on_rejected
9553
98de4c2e2627 util.promise: Fix missing parameters
Matthew Wild <mwild1@gmail.com>
parents: 9552
diff changeset
    37
	wrap_handler(on_fulfilled, resolve, reject, resolve)(promise.value);
9552
800c274928bf util.promise: Ensure chained promises always receive a value/rejection even if an intermediate promise has no handlers
Matthew Wild <mwild1@gmail.com>
parents: 9551
diff changeset
    38
end
800c274928bf util.promise: Ensure chained promises always receive a value/rejection even if an intermediate promise has no handlers
Matthew Wild <mwild1@gmail.com>
parents: 9551
diff changeset
    39
800c274928bf util.promise: Ensure chained promises always receive a value/rejection even if an intermediate promise has no handlers
Matthew Wild <mwild1@gmail.com>
parents: 9551
diff changeset
    40
local function next_rejected(promise, on_fulfilled, on_rejected, resolve, reject) -- luacheck: ignore 212/on_fulfilled
9553
98de4c2e2627 util.promise: Fix missing parameters
Matthew Wild <mwild1@gmail.com>
parents: 9552
diff changeset
    41
	wrap_handler(on_rejected, resolve, reject, reject)(promise.reason);
9459
d54a0e129af8 util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    42
end
d54a0e129af8 util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    43
d54a0e129af8 util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    44
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
    45
	if promise._state ~= "pending" then
d54a0e129af8 util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    46
		return;
d54a0e129af8 util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    47
	end
d54a0e129af8 util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    48
	promise._state = new_state;
d54a0e129af8 util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    49
	promise._next = new_next;
d54a0e129af8 util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    50
	for _, cb in ipairs(cbs) do
d54a0e129af8 util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    51
		cb(value);
d54a0e129af8 util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    52
	end
9749
0dbb285f903e util.promise: Remove references to callbacks after settling promise
Kim Alvefur <zash@zash.se>
parents: 9565
diff changeset
    53
	-- No need to keep references to callbacks
0dbb285f903e util.promise: Remove references to callbacks after settling promise
Kim Alvefur <zash@zash.se>
parents: 9565
diff changeset
    54
	promise._pending_on_fulfilled = nil;
0dbb285f903e util.promise: Remove references to callbacks after settling promise
Kim Alvefur <zash@zash.se>
parents: 9565
diff changeset
    55
	promise._pending_on_rejected = nil;
9459
d54a0e129af8 util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    56
	return true;
d54a0e129af8 util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    57
end
d54a0e129af8 util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    58
d54a0e129af8 util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    59
local function new_resolve_functions(p)
d54a0e129af8 util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    60
	local resolved = false;
d54a0e129af8 util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    61
	local function _resolve(v)
d54a0e129af8 util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    62
		if resolved then return; end
d54a0e129af8 util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    63
		resolved = true;
d54a0e129af8 util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    64
		if is_promise(v) then
d54a0e129af8 util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    65
			v:next(new_resolve_functions(p));
d54a0e129af8 util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    66
		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
    67
			p.value = v;
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
	end
d54a0e129af8 util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    71
	local function _reject(e)
d54a0e129af8 util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    72
		if resolved then return; end
d54a0e129af8 util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    73
		resolved = true;
9561
5fa73fbb047f util.promise: Remove the non-standard ability to pass a promise to reject()
Matthew Wild <mwild1@gmail.com>
parents: 9553
diff changeset
    74
		if 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
    75
			p.reason = e;
d54a0e129af8 util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    76
		end
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
	return _resolve, _reject;
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
11951
073e53b72792 util.promise: Support delayed promise execution
Kim Alvefur <zash@zash.se>
parents: 11490
diff changeset
    81
local next_tick = function (f)
073e53b72792 util.promise: Support delayed promise execution
Kim Alvefur <zash@zash.se>
parents: 11490
diff changeset
    82
	f();
073e53b72792 util.promise: Support delayed promise execution
Kim Alvefur <zash@zash.se>
parents: 11490
diff changeset
    83
end
073e53b72792 util.promise: Support delayed promise execution
Kim Alvefur <zash@zash.se>
parents: 11490
diff changeset
    84
9516
4f4f9823bd1d util.promise: Some code relocation
Matthew Wild <mwild1@gmail.com>
parents: 9515
diff changeset
    85
local function new(f)
4f4f9823bd1d util.promise: Some code relocation
Matthew Wild <mwild1@gmail.com>
parents: 9515
diff changeset
    86
	local p = setmetatable({ _state = "pending", _next = next_pending, _pending_on_fulfilled = {}, _pending_on_rejected = {} }, promise_mt);
4f4f9823bd1d util.promise: Some code relocation
Matthew Wild <mwild1@gmail.com>
parents: 9515
diff changeset
    87
	if f then
11951
073e53b72792 util.promise: Support delayed promise execution
Kim Alvefur <zash@zash.se>
parents: 11490
diff changeset
    88
		next_tick(function()
073e53b72792 util.promise: Support delayed promise execution
Kim Alvefur <zash@zash.se>
parents: 11490
diff changeset
    89
			local resolve, reject = new_resolve_functions(p);
073e53b72792 util.promise: Support delayed promise execution
Kim Alvefur <zash@zash.se>
parents: 11490
diff changeset
    90
			local ok, ret = xpcall(f, debug.traceback, resolve, reject);
073e53b72792 util.promise: Support delayed promise execution
Kim Alvefur <zash@zash.se>
parents: 11490
diff changeset
    91
			if not ok and p._state == "pending" then
073e53b72792 util.promise: Support delayed promise execution
Kim Alvefur <zash@zash.se>
parents: 11490
diff changeset
    92
				reject(ret);
073e53b72792 util.promise: Support delayed promise execution
Kim Alvefur <zash@zash.se>
parents: 11490
diff changeset
    93
			end
073e53b72792 util.promise: Support delayed promise execution
Kim Alvefur <zash@zash.se>
parents: 11490
diff changeset
    94
		end);
9516
4f4f9823bd1d util.promise: Some code relocation
Matthew Wild <mwild1@gmail.com>
parents: 9515
diff changeset
    95
	end
4f4f9823bd1d util.promise: Some code relocation
Matthew Wild <mwild1@gmail.com>
parents: 9515
diff changeset
    96
	return p;
9459
d54a0e129af8 util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    97
end
d54a0e129af8 util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    98
d54a0e129af8 util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    99
local function all(promises)
d54a0e129af8 util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   100
	return new(function (resolve, reject)
11487
24ce9d380475 util.promise: Add support for arbitrary keys in all()/all_settled()
Matthew Wild <mwild1@gmail.com>
parents: 11215
diff changeset
   101
		local settled, results, loop_finished = 0, {}, false;
24ce9d380475 util.promise: Add support for arbitrary keys in all()/all_settled()
Matthew Wild <mwild1@gmail.com>
parents: 11215
diff changeset
   102
		local total = 0;
24ce9d380475 util.promise: Add support for arbitrary keys in all()/all_settled()
Matthew Wild <mwild1@gmail.com>
parents: 11215
diff changeset
   103
		for k, v in pairs(promises) do
11489
7d42ed3a8a40 util.promise: all()/all_settled() pass through non-promise values
Matthew Wild <mwild1@gmail.com>
parents: 11488
diff changeset
   104
			if is_promise(v) then
7d42ed3a8a40 util.promise: all()/all_settled() pass through non-promise values
Matthew Wild <mwild1@gmail.com>
parents: 11488
diff changeset
   105
				total = total + 1;
7d42ed3a8a40 util.promise: all()/all_settled() pass through non-promise values
Matthew Wild <mwild1@gmail.com>
parents: 11488
diff changeset
   106
				v:next(function (value)
7d42ed3a8a40 util.promise: all()/all_settled() pass through non-promise values
Matthew Wild <mwild1@gmail.com>
parents: 11488
diff changeset
   107
					results[k] = value;
7d42ed3a8a40 util.promise: all()/all_settled() pass through non-promise values
Matthew Wild <mwild1@gmail.com>
parents: 11488
diff changeset
   108
					settled = settled + 1;
7d42ed3a8a40 util.promise: all()/all_settled() pass through non-promise values
Matthew Wild <mwild1@gmail.com>
parents: 11488
diff changeset
   109
					if settled == total and loop_finished then
7d42ed3a8a40 util.promise: all()/all_settled() pass through non-promise values
Matthew Wild <mwild1@gmail.com>
parents: 11488
diff changeset
   110
						resolve(results);
7d42ed3a8a40 util.promise: all()/all_settled() pass through non-promise values
Matthew Wild <mwild1@gmail.com>
parents: 11488
diff changeset
   111
					end
7d42ed3a8a40 util.promise: all()/all_settled() pass through non-promise values
Matthew Wild <mwild1@gmail.com>
parents: 11488
diff changeset
   112
				end, reject);
7d42ed3a8a40 util.promise: all()/all_settled() pass through non-promise values
Matthew Wild <mwild1@gmail.com>
parents: 11488
diff changeset
   113
			else
7d42ed3a8a40 util.promise: all()/all_settled() pass through non-promise values
Matthew Wild <mwild1@gmail.com>
parents: 11488
diff changeset
   114
				results[k] = v;
7d42ed3a8a40 util.promise: all()/all_settled() pass through non-promise values
Matthew Wild <mwild1@gmail.com>
parents: 11488
diff changeset
   115
			end
9459
d54a0e129af8 util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   116
		end
11487
24ce9d380475 util.promise: Add support for arbitrary keys in all()/all_settled()
Matthew Wild <mwild1@gmail.com>
parents: 11215
diff changeset
   117
		loop_finished = true;
24ce9d380475 util.promise: Add support for arbitrary keys in all()/all_settled()
Matthew Wild <mwild1@gmail.com>
parents: 11215
diff changeset
   118
		if settled == total then
24ce9d380475 util.promise: Add support for arbitrary keys in all()/all_settled()
Matthew Wild <mwild1@gmail.com>
parents: 11215
diff changeset
   119
			resolve(results);
24ce9d380475 util.promise: Add support for arbitrary keys in all()/all_settled()
Matthew Wild <mwild1@gmail.com>
parents: 11215
diff changeset
   120
		end
9459
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
end
d54a0e129af8 util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   123
10926
7d3dbb9eb3eb util.promise: Add all_settled, which follows semantics of allSettled from ES2020
Matthew Wild <mwild1@gmail.com>
parents: 9749
diff changeset
   124
local function all_settled(promises)
7d3dbb9eb3eb util.promise: Add all_settled, which follows semantics of allSettled from ES2020
Matthew Wild <mwild1@gmail.com>
parents: 9749
diff changeset
   125
	return new(function (resolve)
11487
24ce9d380475 util.promise: Add support for arbitrary keys in all()/all_settled()
Matthew Wild <mwild1@gmail.com>
parents: 11215
diff changeset
   126
		local settled, results, loop_finished = 0, {}, false;
24ce9d380475 util.promise: Add support for arbitrary keys in all()/all_settled()
Matthew Wild <mwild1@gmail.com>
parents: 11215
diff changeset
   127
		local total = 0;
24ce9d380475 util.promise: Add support for arbitrary keys in all()/all_settled()
Matthew Wild <mwild1@gmail.com>
parents: 11215
diff changeset
   128
		for k, v in pairs(promises) do
11489
7d42ed3a8a40 util.promise: all()/all_settled() pass through non-promise values
Matthew Wild <mwild1@gmail.com>
parents: 11488
diff changeset
   129
			if is_promise(v) then
7d42ed3a8a40 util.promise: all()/all_settled() pass through non-promise values
Matthew Wild <mwild1@gmail.com>
parents: 11488
diff changeset
   130
				total = total + 1;
7d42ed3a8a40 util.promise: all()/all_settled() pass through non-promise values
Matthew Wild <mwild1@gmail.com>
parents: 11488
diff changeset
   131
				v:next(function (value)
7d42ed3a8a40 util.promise: all()/all_settled() pass through non-promise values
Matthew Wild <mwild1@gmail.com>
parents: 11488
diff changeset
   132
					results[k] = { status = "fulfilled", value = value };
7d42ed3a8a40 util.promise: all()/all_settled() pass through non-promise values
Matthew Wild <mwild1@gmail.com>
parents: 11488
diff changeset
   133
					settled = settled + 1;
7d42ed3a8a40 util.promise: all()/all_settled() pass through non-promise values
Matthew Wild <mwild1@gmail.com>
parents: 11488
diff changeset
   134
					if settled == total and loop_finished then
7d42ed3a8a40 util.promise: all()/all_settled() pass through non-promise values
Matthew Wild <mwild1@gmail.com>
parents: 11488
diff changeset
   135
						resolve(results);
7d42ed3a8a40 util.promise: all()/all_settled() pass through non-promise values
Matthew Wild <mwild1@gmail.com>
parents: 11488
diff changeset
   136
					end
7d42ed3a8a40 util.promise: all()/all_settled() pass through non-promise values
Matthew Wild <mwild1@gmail.com>
parents: 11488
diff changeset
   137
				end, function (e)
7d42ed3a8a40 util.promise: all()/all_settled() pass through non-promise values
Matthew Wild <mwild1@gmail.com>
parents: 11488
diff changeset
   138
					results[k] = { status = "rejected", reason = e };
7d42ed3a8a40 util.promise: all()/all_settled() pass through non-promise values
Matthew Wild <mwild1@gmail.com>
parents: 11488
diff changeset
   139
					settled = settled + 1;
7d42ed3a8a40 util.promise: all()/all_settled() pass through non-promise values
Matthew Wild <mwild1@gmail.com>
parents: 11488
diff changeset
   140
					if settled == total and loop_finished then
7d42ed3a8a40 util.promise: all()/all_settled() pass through non-promise values
Matthew Wild <mwild1@gmail.com>
parents: 11488
diff changeset
   141
						resolve(results);
7d42ed3a8a40 util.promise: all()/all_settled() pass through non-promise values
Matthew Wild <mwild1@gmail.com>
parents: 11488
diff changeset
   142
					end
7d42ed3a8a40 util.promise: all()/all_settled() pass through non-promise values
Matthew Wild <mwild1@gmail.com>
parents: 11488
diff changeset
   143
				end);
7d42ed3a8a40 util.promise: all()/all_settled() pass through non-promise values
Matthew Wild <mwild1@gmail.com>
parents: 11488
diff changeset
   144
			else
7d42ed3a8a40 util.promise: all()/all_settled() pass through non-promise values
Matthew Wild <mwild1@gmail.com>
parents: 11488
diff changeset
   145
				results[k] = v;
7d42ed3a8a40 util.promise: all()/all_settled() pass through non-promise values
Matthew Wild <mwild1@gmail.com>
parents: 11488
diff changeset
   146
			end
10926
7d3dbb9eb3eb util.promise: Add all_settled, which follows semantics of allSettled from ES2020
Matthew Wild <mwild1@gmail.com>
parents: 9749
diff changeset
   147
		end
11487
24ce9d380475 util.promise: Add support for arbitrary keys in all()/all_settled()
Matthew Wild <mwild1@gmail.com>
parents: 11215
diff changeset
   148
		loop_finished = true;
24ce9d380475 util.promise: Add support for arbitrary keys in all()/all_settled()
Matthew Wild <mwild1@gmail.com>
parents: 11215
diff changeset
   149
		if settled == total then
24ce9d380475 util.promise: Add support for arbitrary keys in all()/all_settled()
Matthew Wild <mwild1@gmail.com>
parents: 11215
diff changeset
   150
			resolve(results);
24ce9d380475 util.promise: Add support for arbitrary keys in all()/all_settled()
Matthew Wild <mwild1@gmail.com>
parents: 11215
diff changeset
   151
		end
10926
7d3dbb9eb3eb util.promise: Add all_settled, which follows semantics of allSettled from ES2020
Matthew Wild <mwild1@gmail.com>
parents: 9749
diff changeset
   152
	end);
7d3dbb9eb3eb util.promise: Add all_settled, which follows semantics of allSettled from ES2020
Matthew Wild <mwild1@gmail.com>
parents: 9749
diff changeset
   153
end
7d3dbb9eb3eb util.promise: Add all_settled, which follows semantics of allSettled from ES2020
Matthew Wild <mwild1@gmail.com>
parents: 9749
diff changeset
   154
11490
78d843faaffc util.promise: Switch order of parameters to join()
Matthew Wild <mwild1@gmail.com>
parents: 11489
diff changeset
   155
local function join(handler, ...)
11488
a0120e935442 util.promise: Add join() convenience method
Matthew Wild <mwild1@gmail.com>
parents: 11487
diff changeset
   156
	local promises, n = { ... }, select("#", ...);
a0120e935442 util.promise: Add join() convenience method
Matthew Wild <mwild1@gmail.com>
parents: 11487
diff changeset
   157
	return all(promises):next(function (results)
11490
78d843faaffc util.promise: Switch order of parameters to join()
Matthew Wild <mwild1@gmail.com>
parents: 11489
diff changeset
   158
		return handler(unpack(results, 1, n));
11488
a0120e935442 util.promise: Add join() convenience method
Matthew Wild <mwild1@gmail.com>
parents: 11487
diff changeset
   159
	end);
a0120e935442 util.promise: Add join() convenience method
Matthew Wild <mwild1@gmail.com>
parents: 11487
diff changeset
   160
end
a0120e935442 util.promise: Add join() convenience method
Matthew Wild <mwild1@gmail.com>
parents: 11487
diff changeset
   161
9459
d54a0e129af8 util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   162
local function race(promises)
d54a0e129af8 util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   163
	return new(function (resolve, reject)
d54a0e129af8 util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   164
		for i = 1, #promises do
d54a0e129af8 util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   165
			promises[i]:next(resolve, reject);
d54a0e129af8 util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   166
		end
d54a0e129af8 util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   167
	end);
d54a0e129af8 util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   168
end
d54a0e129af8 util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   169
d54a0e129af8 util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   170
local function resolve(v)
d54a0e129af8 util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   171
	return new(function (_resolve)
d54a0e129af8 util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   172
		_resolve(v);
d54a0e129af8 util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   173
	end);
d54a0e129af8 util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   174
end
d54a0e129af8 util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   175
d54a0e129af8 util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   176
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
   177
	return new(function (_, _reject)
9459
d54a0e129af8 util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   178
		_reject(v);
d54a0e129af8 util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   179
	end);
d54a0e129af8 util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   180
end
d54a0e129af8 util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   181
9520
b1c6ede17592 util.promise: Add promise.try()
Matthew Wild <mwild1@gmail.com>
parents: 9518
diff changeset
   182
local function try(f)
b1c6ede17592 util.promise: Add promise.try()
Matthew Wild <mwild1@gmail.com>
parents: 9518
diff changeset
   183
	return resolve():next(function () return f(); end);
b1c6ede17592 util.promise: Add promise.try()
Matthew Wild <mwild1@gmail.com>
parents: 9518
diff changeset
   184
end
b1c6ede17592 util.promise: Add promise.try()
Matthew Wild <mwild1@gmail.com>
parents: 9518
diff changeset
   185
9516
4f4f9823bd1d util.promise: Some code relocation
Matthew Wild <mwild1@gmail.com>
parents: 9515
diff changeset
   186
function promise_methods:next(on_fulfilled, on_rejected)
4f4f9823bd1d util.promise: Some code relocation
Matthew Wild <mwild1@gmail.com>
parents: 9515
diff changeset
   187
	return new(function (resolve, reject) --luacheck: ignore 431/resolve 431/reject
9552
800c274928bf util.promise: Ensure chained promises always receive a value/rejection even if an intermediate promise has no handlers
Matthew Wild <mwild1@gmail.com>
parents: 9551
diff changeset
   188
		self:_next(on_fulfilled, on_rejected, resolve, reject);
9516
4f4f9823bd1d util.promise: Some code relocation
Matthew Wild <mwild1@gmail.com>
parents: 9515
diff changeset
   189
	end);
4f4f9823bd1d util.promise: Some code relocation
Matthew Wild <mwild1@gmail.com>
parents: 9515
diff changeset
   190
end
4f4f9823bd1d util.promise: Some code relocation
Matthew Wild <mwild1@gmail.com>
parents: 9515
diff changeset
   191
4f4f9823bd1d util.promise: Some code relocation
Matthew Wild <mwild1@gmail.com>
parents: 9515
diff changeset
   192
function promise_methods:catch(on_rejected)
4f4f9823bd1d util.promise: Some code relocation
Matthew Wild <mwild1@gmail.com>
parents: 9515
diff changeset
   193
	return self:next(nil, on_rejected);
4f4f9823bd1d util.promise: Some code relocation
Matthew Wild <mwild1@gmail.com>
parents: 9515
diff changeset
   194
end
4f4f9823bd1d util.promise: Some code relocation
Matthew Wild <mwild1@gmail.com>
parents: 9515
diff changeset
   195
9517
9db707a86a25 util.promise: Add promise:finally()
Matthew Wild <mwild1@gmail.com>
parents: 9516
diff changeset
   196
function promise_methods:finally(on_finally)
9db707a86a25 util.promise: Add promise:finally()
Matthew Wild <mwild1@gmail.com>
parents: 9516
diff changeset
   197
	local function _on_finally(value) on_finally(); return value; end
9db707a86a25 util.promise: Add promise:finally()
Matthew Wild <mwild1@gmail.com>
parents: 9516
diff changeset
   198
	local function _on_catch_finally(err) on_finally(); return reject(err); end
9db707a86a25 util.promise: Add promise:finally()
Matthew Wild <mwild1@gmail.com>
parents: 9516
diff changeset
   199
	return self:next(_on_finally, _on_catch_finally);
9db707a86a25 util.promise: Add promise:finally()
Matthew Wild <mwild1@gmail.com>
parents: 9516
diff changeset
   200
end
9db707a86a25 util.promise: Add promise:finally()
Matthew Wild <mwild1@gmail.com>
parents: 9516
diff changeset
   201
9459
d54a0e129af8 util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   202
return {
d54a0e129af8 util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   203
	new = new;
d54a0e129af8 util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   204
	resolve = resolve;
11488
a0120e935442 util.promise: Add join() convenience method
Matthew Wild <mwild1@gmail.com>
parents: 11487
diff changeset
   205
	join = join;
9459
d54a0e129af8 util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   206
	reject = reject;
d54a0e129af8 util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   207
	all = all;
10926
7d3dbb9eb3eb util.promise: Add all_settled, which follows semantics of allSettled from ES2020
Matthew Wild <mwild1@gmail.com>
parents: 9749
diff changeset
   208
	all_settled = all_settled;
9459
d54a0e129af8 util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   209
	race = race;
9520
b1c6ede17592 util.promise: Add promise.try()
Matthew Wild <mwild1@gmail.com>
parents: 9518
diff changeset
   210
	try = try;
9551
a83afc22e9d7 util.promise: Export is_promise()
Matthew Wild <mwild1@gmail.com>
parents: 9549
diff changeset
   211
	is_promise = is_promise;
11951
073e53b72792 util.promise: Support delayed promise execution
Kim Alvefur <zash@zash.se>
parents: 11490
diff changeset
   212
	set_nexttick = function(new_next_tick) next_tick = new_next_tick; end;
9459
d54a0e129af8 util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   213
}