util/promise.lua
author Kim Alvefur <zash@zash.se>
Tue, 14 May 2024 17:07:47 +0200
changeset 13494 6f840763fc73
parent 12979 d10957394a3c
permissions -rw-r--r--
net.server_epoll: Add support for systemd socket activation Allows creating listening sockets and accepting client connections before Prosody starts. This is unlike normal Prosody dynamic resource management, where ports may added and removed at any time, and the ports defined by the config. Weird things happen if these are closed (e.g. due to reload) so here we prevent closing and ensure sockets are reused when opened again.
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
12979
d10957394a3c util: Prefix module imports with prosody namespace
Kim Alvefur <zash@zash.se>
parents: 12754
diff changeset
     4
local xpcall = require "prosody.util.xpcall".xpcall;
12593
39ae08180c81 compat: Remove handling of Lua 5.1 location of 'unpack' function
Kim Alvefur <zash@zash.se>
parents: 11951
diff changeset
     5
local unpack = table.unpack;
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 function _resolve(v)
d54a0e129af8 util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    61
		if is_promise(v) then
d54a0e129af8 util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    62
			v:next(new_resolve_functions(p));
d54a0e129af8 util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    63
		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
    64
			p.value = v;
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
d54a0e129af8 util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    67
	end
d54a0e129af8 util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    68
	local function _reject(e)
9561
5fa73fbb047f util.promise: Remove the non-standard ability to pass a promise to reject()
Matthew Wild <mwild1@gmail.com>
parents: 9553
diff changeset
    69
		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
    70
			p.reason = e;
d54a0e129af8 util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    71
		end
d54a0e129af8 util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    72
	end
d54a0e129af8 util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    73
	return _resolve, _reject;
d54a0e129af8 util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    74
end
d54a0e129af8 util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    75
11951
073e53b72792 util.promise: Support delayed promise execution
Kim Alvefur <zash@zash.se>
parents: 11490
diff changeset
    76
local next_tick = function (f)
073e53b72792 util.promise: Support delayed promise execution
Kim Alvefur <zash@zash.se>
parents: 11490
diff changeset
    77
	f();
073e53b72792 util.promise: Support delayed promise execution
Kim Alvefur <zash@zash.se>
parents: 11490
diff changeset
    78
end
073e53b72792 util.promise: Support delayed promise execution
Kim Alvefur <zash@zash.se>
parents: 11490
diff changeset
    79
9516
4f4f9823bd1d util.promise: Some code relocation
Matthew Wild <mwild1@gmail.com>
parents: 9515
diff changeset
    80
local function new(f)
4f4f9823bd1d util.promise: Some code relocation
Matthew Wild <mwild1@gmail.com>
parents: 9515
diff changeset
    81
	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
    82
	if f then
11951
073e53b72792 util.promise: Support delayed promise execution
Kim Alvefur <zash@zash.se>
parents: 11490
diff changeset
    83
		next_tick(function()
073e53b72792 util.promise: Support delayed promise execution
Kim Alvefur <zash@zash.se>
parents: 11490
diff changeset
    84
			local resolve, reject = new_resolve_functions(p);
073e53b72792 util.promise: Support delayed promise execution
Kim Alvefur <zash@zash.se>
parents: 11490
diff changeset
    85
			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
    86
			if not ok and p._state == "pending" then
073e53b72792 util.promise: Support delayed promise execution
Kim Alvefur <zash@zash.se>
parents: 11490
diff changeset
    87
				reject(ret);
073e53b72792 util.promise: Support delayed promise execution
Kim Alvefur <zash@zash.se>
parents: 11490
diff changeset
    88
			end
073e53b72792 util.promise: Support delayed promise execution
Kim Alvefur <zash@zash.se>
parents: 11490
diff changeset
    89
		end);
9516
4f4f9823bd1d util.promise: Some code relocation
Matthew Wild <mwild1@gmail.com>
parents: 9515
diff changeset
    90
	end
4f4f9823bd1d util.promise: Some code relocation
Matthew Wild <mwild1@gmail.com>
parents: 9515
diff changeset
    91
	return p;
9459
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)
11487
24ce9d380475 util.promise: Add support for arbitrary keys in all()/all_settled()
Matthew Wild <mwild1@gmail.com>
parents: 11215
diff changeset
    96
		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
    97
		local total = 0;
24ce9d380475 util.promise: Add support for arbitrary keys in all()/all_settled()
Matthew Wild <mwild1@gmail.com>
parents: 11215
diff changeset
    98
		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
    99
			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
   100
				total = total + 1;
7d42ed3a8a40 util.promise: all()/all_settled() pass through non-promise values
Matthew Wild <mwild1@gmail.com>
parents: 11488
diff changeset
   101
				v:next(function (value)
7d42ed3a8a40 util.promise: all()/all_settled() pass through non-promise values
Matthew Wild <mwild1@gmail.com>
parents: 11488
diff changeset
   102
					results[k] = value;
7d42ed3a8a40 util.promise: all()/all_settled() pass through non-promise values
Matthew Wild <mwild1@gmail.com>
parents: 11488
diff changeset
   103
					settled = settled + 1;
7d42ed3a8a40 util.promise: all()/all_settled() pass through non-promise values
Matthew Wild <mwild1@gmail.com>
parents: 11488
diff changeset
   104
					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
   105
						resolve(results);
7d42ed3a8a40 util.promise: all()/all_settled() pass through non-promise values
Matthew Wild <mwild1@gmail.com>
parents: 11488
diff changeset
   106
					end
7d42ed3a8a40 util.promise: all()/all_settled() pass through non-promise values
Matthew Wild <mwild1@gmail.com>
parents: 11488
diff changeset
   107
				end, reject);
7d42ed3a8a40 util.promise: all()/all_settled() pass through non-promise values
Matthew Wild <mwild1@gmail.com>
parents: 11488
diff changeset
   108
			else
7d42ed3a8a40 util.promise: all()/all_settled() pass through non-promise values
Matthew Wild <mwild1@gmail.com>
parents: 11488
diff changeset
   109
				results[k] = v;
7d42ed3a8a40 util.promise: all()/all_settled() pass through non-promise values
Matthew Wild <mwild1@gmail.com>
parents: 11488
diff changeset
   110
			end
9459
d54a0e129af8 util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   111
		end
11487
24ce9d380475 util.promise: Add support for arbitrary keys in all()/all_settled()
Matthew Wild <mwild1@gmail.com>
parents: 11215
diff changeset
   112
		loop_finished = true;
24ce9d380475 util.promise: Add support for arbitrary keys in all()/all_settled()
Matthew Wild <mwild1@gmail.com>
parents: 11215
diff changeset
   113
		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
   114
			resolve(results);
24ce9d380475 util.promise: Add support for arbitrary keys in all()/all_settled()
Matthew Wild <mwild1@gmail.com>
parents: 11215
diff changeset
   115
		end
9459
d54a0e129af8 util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   116
	end);
d54a0e129af8 util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   117
end
d54a0e129af8 util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   118
10926
7d3dbb9eb3eb util.promise: Add all_settled, which follows semantics of allSettled from ES2020
Matthew Wild <mwild1@gmail.com>
parents: 9749
diff changeset
   119
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
   120
	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
   121
		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
   122
		local total = 0;
24ce9d380475 util.promise: Add support for arbitrary keys in all()/all_settled()
Matthew Wild <mwild1@gmail.com>
parents: 11215
diff changeset
   123
		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
   124
			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
   125
				total = total + 1;
7d42ed3a8a40 util.promise: all()/all_settled() pass through non-promise values
Matthew Wild <mwild1@gmail.com>
parents: 11488
diff changeset
   126
				v:next(function (value)
7d42ed3a8a40 util.promise: all()/all_settled() pass through non-promise values
Matthew Wild <mwild1@gmail.com>
parents: 11488
diff changeset
   127
					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
   128
					settled = settled + 1;
7d42ed3a8a40 util.promise: all()/all_settled() pass through non-promise values
Matthew Wild <mwild1@gmail.com>
parents: 11488
diff changeset
   129
					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
   130
						resolve(results);
7d42ed3a8a40 util.promise: all()/all_settled() pass through non-promise values
Matthew Wild <mwild1@gmail.com>
parents: 11488
diff changeset
   131
					end
7d42ed3a8a40 util.promise: all()/all_settled() pass through non-promise values
Matthew Wild <mwild1@gmail.com>
parents: 11488
diff changeset
   132
				end, function (e)
7d42ed3a8a40 util.promise: all()/all_settled() pass through non-promise values
Matthew Wild <mwild1@gmail.com>
parents: 11488
diff changeset
   133
					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
   134
					settled = settled + 1;
7d42ed3a8a40 util.promise: all()/all_settled() pass through non-promise values
Matthew Wild <mwild1@gmail.com>
parents: 11488
diff changeset
   135
					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
   136
						resolve(results);
7d42ed3a8a40 util.promise: all()/all_settled() pass through non-promise values
Matthew Wild <mwild1@gmail.com>
parents: 11488
diff changeset
   137
					end
7d42ed3a8a40 util.promise: all()/all_settled() pass through non-promise values
Matthew Wild <mwild1@gmail.com>
parents: 11488
diff changeset
   138
				end);
7d42ed3a8a40 util.promise: all()/all_settled() pass through non-promise values
Matthew Wild <mwild1@gmail.com>
parents: 11488
diff changeset
   139
			else
7d42ed3a8a40 util.promise: all()/all_settled() pass through non-promise values
Matthew Wild <mwild1@gmail.com>
parents: 11488
diff changeset
   140
				results[k] = v;
7d42ed3a8a40 util.promise: all()/all_settled() pass through non-promise values
Matthew Wild <mwild1@gmail.com>
parents: 11488
diff changeset
   141
			end
10926
7d3dbb9eb3eb util.promise: Add all_settled, which follows semantics of allSettled from ES2020
Matthew Wild <mwild1@gmail.com>
parents: 9749
diff changeset
   142
		end
11487
24ce9d380475 util.promise: Add support for arbitrary keys in all()/all_settled()
Matthew Wild <mwild1@gmail.com>
parents: 11215
diff changeset
   143
		loop_finished = true;
24ce9d380475 util.promise: Add support for arbitrary keys in all()/all_settled()
Matthew Wild <mwild1@gmail.com>
parents: 11215
diff changeset
   144
		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
   145
			resolve(results);
24ce9d380475 util.promise: Add support for arbitrary keys in all()/all_settled()
Matthew Wild <mwild1@gmail.com>
parents: 11215
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);
7d3dbb9eb3eb util.promise: Add all_settled, which follows semantics of allSettled from ES2020
Matthew Wild <mwild1@gmail.com>
parents: 9749
diff changeset
   148
end
7d3dbb9eb3eb util.promise: Add all_settled, which follows semantics of allSettled from ES2020
Matthew Wild <mwild1@gmail.com>
parents: 9749
diff changeset
   149
11490
78d843faaffc util.promise: Switch order of parameters to join()
Matthew Wild <mwild1@gmail.com>
parents: 11489
diff changeset
   150
local function join(handler, ...)
11488
a0120e935442 util.promise: Add join() convenience method
Matthew Wild <mwild1@gmail.com>
parents: 11487
diff changeset
   151
	local promises, n = { ... }, select("#", ...);
a0120e935442 util.promise: Add join() convenience method
Matthew Wild <mwild1@gmail.com>
parents: 11487
diff changeset
   152
	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
   153
		return handler(unpack(results, 1, n));
11488
a0120e935442 util.promise: Add join() convenience method
Matthew Wild <mwild1@gmail.com>
parents: 11487
diff changeset
   154
	end);
a0120e935442 util.promise: Add join() convenience method
Matthew Wild <mwild1@gmail.com>
parents: 11487
diff changeset
   155
end
a0120e935442 util.promise: Add join() convenience method
Matthew Wild <mwild1@gmail.com>
parents: 11487
diff changeset
   156
9459
d54a0e129af8 util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   157
local function race(promises)
d54a0e129af8 util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   158
	return new(function (resolve, reject)
d54a0e129af8 util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   159
		for i = 1, #promises do
d54a0e129af8 util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   160
			promises[i]:next(resolve, reject);
d54a0e129af8 util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   161
		end
d54a0e129af8 util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   162
	end);
d54a0e129af8 util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   163
end
d54a0e129af8 util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   164
d54a0e129af8 util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   165
local function resolve(v)
d54a0e129af8 util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   166
	return new(function (_resolve)
d54a0e129af8 util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   167
		_resolve(v);
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
end
d54a0e129af8 util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   170
d54a0e129af8 util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   171
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
   172
	return new(function (_, _reject)
9459
d54a0e129af8 util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   173
		_reject(v);
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
end
d54a0e129af8 util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   176
9520
b1c6ede17592 util.promise: Add promise.try()
Matthew Wild <mwild1@gmail.com>
parents: 9518
diff changeset
   177
local function try(f)
b1c6ede17592 util.promise: Add promise.try()
Matthew Wild <mwild1@gmail.com>
parents: 9518
diff changeset
   178
	return resolve():next(function () return f(); end);
b1c6ede17592 util.promise: Add promise.try()
Matthew Wild <mwild1@gmail.com>
parents: 9518
diff changeset
   179
end
b1c6ede17592 util.promise: Add promise.try()
Matthew Wild <mwild1@gmail.com>
parents: 9518
diff changeset
   180
9516
4f4f9823bd1d util.promise: Some code relocation
Matthew Wild <mwild1@gmail.com>
parents: 9515
diff changeset
   181
function promise_methods:next(on_fulfilled, on_rejected)
4f4f9823bd1d util.promise: Some code relocation
Matthew Wild <mwild1@gmail.com>
parents: 9515
diff changeset
   182
	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
   183
		self:_next(on_fulfilled, on_rejected, resolve, reject);
9516
4f4f9823bd1d util.promise: Some code relocation
Matthew Wild <mwild1@gmail.com>
parents: 9515
diff changeset
   184
	end);
4f4f9823bd1d util.promise: Some code relocation
Matthew Wild <mwild1@gmail.com>
parents: 9515
diff changeset
   185
end
4f4f9823bd1d util.promise: Some code relocation
Matthew Wild <mwild1@gmail.com>
parents: 9515
diff changeset
   186
4f4f9823bd1d util.promise: Some code relocation
Matthew Wild <mwild1@gmail.com>
parents: 9515
diff changeset
   187
function promise_methods:catch(on_rejected)
4f4f9823bd1d util.promise: Some code relocation
Matthew Wild <mwild1@gmail.com>
parents: 9515
diff changeset
   188
	return self:next(nil, on_rejected);
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
9517
9db707a86a25 util.promise: Add promise:finally()
Matthew Wild <mwild1@gmail.com>
parents: 9516
diff changeset
   191
function promise_methods:finally(on_finally)
9db707a86a25 util.promise: Add promise:finally()
Matthew Wild <mwild1@gmail.com>
parents: 9516
diff changeset
   192
	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
   193
	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
   194
	return self:next(_on_finally, _on_catch_finally);
9db707a86a25 util.promise: Add promise:finally()
Matthew Wild <mwild1@gmail.com>
parents: 9516
diff changeset
   195
end
9db707a86a25 util.promise: Add promise:finally()
Matthew Wild <mwild1@gmail.com>
parents: 9516
diff changeset
   196
9459
d54a0e129af8 util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   197
return {
d54a0e129af8 util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   198
	new = new;
d54a0e129af8 util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   199
	resolve = resolve;
11488
a0120e935442 util.promise: Add join() convenience method
Matthew Wild <mwild1@gmail.com>
parents: 11487
diff changeset
   200
	join = join;
9459
d54a0e129af8 util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   201
	reject = reject;
d54a0e129af8 util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   202
	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
   203
	all_settled = all_settled;
9459
d54a0e129af8 util.promise: ES6-like API for promises
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   204
	race = race;
9520
b1c6ede17592 util.promise: Add promise.try()
Matthew Wild <mwild1@gmail.com>
parents: 9518
diff changeset
   205
	try = try;
9551
a83afc22e9d7 util.promise: Export is_promise()
Matthew Wild <mwild1@gmail.com>
parents: 9549
diff changeset
   206
	is_promise = is_promise;
11951
073e53b72792 util.promise: Support delayed promise execution
Kim Alvefur <zash@zash.se>
parents: 11490
diff changeset
   207
	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
   208
}