util/promise.lua
author Kim Alvefur <zash@zash.se>
Sun, 27 Aug 2023 15:46:19 +0200
branch0.12
changeset 13258 a2ba3f06dcf4
parent 11951 073e53b72792
child 12593 39ae08180c81
permissions -rw-r--r--
util.prosodyctl.check: Correct modern replacement for 'disallow_s2s' The code would have suggested adding to modules_enabled instead of modules_disabled
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
}