function Promise._all(k,t,i)if type(t)~="\116\097\098\108\101"then error(string.format(ERROR_NON_LIST,"\080\114\111\109\105\115\101\046\097\108\108"),3)end for k,t in pairs(t)do if not Promise.is(t)then error(string.format(ERROR_NON_PROMISE_IN_LIST,"\080\114\111\109\105\115\101\046\097\108\108",tostring(k)),3)end end if#t==0 or i==0 then return Promise.resolve({})end return Promise._new(k,function(k,r,y)local M={}local P={}local v=0 local F=0 local g=false local function E()for k,t in ipairs(P)do t:cancel()end end local function H(r,...)if g then return end v=v+1 if i==nil then M[r]=...else M[v]=...end if v>=(i or#t)then g=true k(M)E()end end y(E)for k,y in ipairs(t)do P[k]=y:andThen(function(...)H(k,...)end,function(...)F=F+1 if i==nil or#t-F<i then E()g=true r(...)end end)end if g then E()end end)end function Promise.all(...)local k={...}if type(k[1])=="\116\097\098\108\101"and not Promise.is(k[1])then k=k[1]end return Promise._all(debug.traceback(nil,2),k)end function Promise.fold(k,t,i)assert(type(k)=="\116\097\098\108\101","\066\097\100 \097\114\103\117\109\101\110\116 \035\049 \116\111 \080\114\111\109\105\115\101\046\102\111\108\100\058 \109\117\115\116 \098\101 \097 \116\097\098\108\101")assert(type(t)=="\102\117\110\099\116\105\111\110","\066\097\100 \097\114\103\117\109\101\110\116 \035\050 \116\111 \080\114\111\109\105\115\101\046\102\111\108\100\058 \109\117\115\116 \098\101 \097 \102\117\110\099\116\105\111\110")local r=Promise.resolve(i)return(Promise.each(k,function(k,i)r=r:andThen(function(r)return t(r,k,i)end)end)):andThenReturn(r)end function Promise.some(k,t)assert(type(t)=="\110\117\109\098\101\114","\066\097\100 \097\114\103\117\109\101\110\116 \035\050 \116\111 \080\114\111\109\105\115\101\046\115\111\109\101\058 \109\117\115\116 \098\101 \097 \110\117\109\098\101\114")return Promise._all(debug.traceback(nil,2),k,t)end function Promise.any(k)return(Promise._all(debug.traceback(nil,2),k,1)):andThen(function(k)return k[1]end)end function Promise.allSettled(k)if type(k)~="\116\097\098\108\101"then error(string.format(ERROR_NON_LIST,"\080\114\111\109\105\115\101\046\097\108\108\083\101\116\116\108\101\100"),2)end for k,t in pairs(k)do if not Promise.is(t)then error(string.format(ERROR_NON_PROMISE_IN_LIST,"\080\114\111\109\105\115\101\046\097\108\108\083\101\116\116\108\101\100",tostring(k)),2)end end if#k==0 then return Promise.resolve({})end return Promise._new(debug.traceback(nil,2),function(t,i,r)local y={}local M={}local P=0 local function v(i,...)P=P+1 y[i]=...if P>=#k then t(y)end end r(function()for k,t in ipairs(M)do t:cancel()end end)for k,t in ipairs(k)do M[k]=t:finally(function(...)v(k,...)end)end end)end
--[[
	Returns a new promise that:
		* is resolved when all input promises resolve
		* is rejected if ANY input promises reject
]]
function Promise._all(traceback, promises, amount)
	if type(promises) ~= "table" then
		error(string.format(ERROR_NON_LIST, "Promise.all"), 3)
	end

	-- We need to check that each value is a promise here so that we can produce
	-- a proper error rather than a rejected promise with our error.
	for i, promise in pairs(promises) do
		if not Promise.is(promise) then
			error(string.format(ERROR_NON_PROMISE_IN_LIST, "Promise.all", tostring(i)), 3)
		end
	end

	-- If there are no values then return an already resolved promise.
	if #promises == 0 or amount == 0 then
		return Promise.resolve({})
	end

	return Promise._new(traceback, function(resolve, reject, onCancel)
		-- An array to contain our resolved values from the given promises.
		local resolvedValues = {}
		local newPromises = {}

		-- Keep a count of resolved promises because just checking the resolved
		-- values length wouldn't account for promises that resolve with nil.
		local resolvedCount = 0
		local rejectedCount = 0
		local done = false

		local function cancel()
			for _, promise in ipairs(newPromises) do
				promise:cancel()
			end
		end

		-- Called when a single value is resolved and resolves if all are done.
		local function resolveOne(i, ...)
			if done then
				return
			end

			resolvedCount = resolvedCount + 1

			if amount == nil then
				resolvedValues[i] = ...
			else
				resolvedValues[resolvedCount] = ...
			end

			if resolvedCount >= (amount or #promises) then
				done = true
				resolve(resolvedValues)
				cancel()
			end
		end

		onCancel(cancel)

		-- We can assume the values inside `promises` are all promises since we
		-- checked above.
		for i, promise in ipairs(promises) do
			newPromises[i] = promise:andThen(function(...)
				resolveOne(i, ...)
			end, function(...)
				rejectedCount = rejectedCount + 1

				if amount == nil or #promises - rejectedCount < amount then
					cancel()
					done = true

					reject(...)
				end
			end)
		end

		if done then
			cancel()
		end
	end)
end

function Promise.all(...)
	local promises = { ... }

	-- check if we've been given a list of promises, not just a variable number of promises
	if type(promises[1]) == "table" and not Promise.is(promises[1]) then
		-- we've been given a table of promises already
		promises = promises[1]
	end

	return Promise._all(debug.traceback(nil, 2), promises)
end

function Promise.fold(list, callback, initialValue)
	assert(type(list) == "table", "Bad argument #1 to Promise.fold: must be a table")
	assert(type(callback) == "function", "Bad argument #2 to Promise.fold: must be a function")

	local accumulator = Promise.resolve(initialValue)
	return Promise.each(list, function(resolvedElement, i)
		accumulator = accumulator:andThen(function(previousValueResolved)
			return callback(previousValueResolved, resolvedElement, i)
		end)
	end):andThenReturn(accumulator)
end

function Promise.some(promises, amount)
	assert(type(amount) == "number", "Bad argument #2 to Promise.some: must be a number")

	return Promise._all(debug.traceback(nil, 2), promises, amount)
end

function Promise.any(promises)
	return Promise._all(debug.traceback(nil, 2), promises, 1):andThen(function(values)
		return values[1]
	end)
end

function Promise.allSettled(promises)
	if type(promises) ~= "table" then
		error(string.format(ERROR_NON_LIST, "Promise.allSettled"), 2)
	end

	-- We need to check that each value is a promise here so that we can produce
	-- a proper error rather than a rejected promise with our error.
	for i, promise in pairs(promises) do
		if not Promise.is(promise) then
			error(string.format(ERROR_NON_PROMISE_IN_LIST, "Promise.allSettled", tostring(i)), 2)
		end
	end

	-- If there are no values then return an already resolved promise.
	if #promises == 0 then
		return Promise.resolve({})
	end

	return Promise._new(debug.traceback(nil, 2), function(resolve, _, onCancel)
		-- An array to contain our resolved values from the given promises.
		local fates = {}
		local newPromises = {}

		-- Keep a count of resolved promises because just checking the resolved
		-- values length wouldn't account for promises that resolve with nil.
		local finishedCount = 0

		-- Called when a single value is resolved and resolves if all are done.
		local function resolveOne(i, ...)
			finishedCount = finishedCount + 1

			fates[i] = ...

			if finishedCount >= #promises then
				resolve(fates)
			end
		end

		onCancel(function()
			for _, promise in ipairs(newPromises) do
				promise:cancel()
			end
		end)

		-- We can assume the values inside `promises` are all promises since we
		-- checked above.
		for i, promise in ipairs(promises) do
			newPromises[i] = promise:finally(function(...)
				resolveOne(i, ...)
			end)
		end
	end)
end
