function Promise.each(q,K)assert(type(q)=="\116\097\098\108\101",string.format(ERROR_NON_LIST,"\080\114\111\109\105\115\101\046\101\097\099\104"))assert(type(K)=="\102\117\110\099\116\105\111\110",string.format(ERROR_NON_FUNCTION,"\080\114\111\109\105\115\101\046\101\097\099\104"))return Promise._new(debug.traceback(nil,2),function(k,B,f)local H={}local z={}local N=false local function G()for q,K in ipairs(z)do K:cancel()end end f(function()N=true G()end)local g={}for q,K in ipairs(q)do if Promise.is(K)then if K:getStatus()==Promise.Status.Cancelled then G()return B(Error.new({error="\080\114\111\109\105\115\101 \105\115 \099\097\110\099\101\108\108\101\100",kind=Error.Kind.AlreadyCancelled;context=string.format("\084\104\101 \080\114\111\109\105\115\101 \116\104\097\116 \119\097\115 \112\097\114\116 \111\102 \116\104\101 \097\114\114\097\121 \097\116 \105\110\100\101\120 \037\100 \112\097\115\115\101\100 \105\110\116\111 \080\114\111\109\105\115\101\046\101\097\099\104 \119\097\115 \097\108\114\101\097\100\121 \099\097\110\099\101\108\108\101\100 \119\104\101\110 \080\114\111\109\105\115\101\046\101\097\099\104 \098\101\103\097\110\046\n\n\084\104\097\116 \080\114\111\109\105\115\101 \119\097\115 \099\114\101\097\116\101\100 \097\116\058\n\n\037\115",q,K._source)}))elseif K:getStatus()==Promise.Status.Rejected then G()return B(select(2,K:await()))end local k=K:andThen(function(...)return...end)table.insert(z,k)g[q]=k else g[q]=K end end for q,k in ipairs(g)do if Promise.is(k)then local q q,k=k:await()if not q then G()return B(k)end end if N then return end local f=Promise.resolve(K(k,q))table.insert(z,f)local g,A=f:await()if not g then G()return B(A)end H[q]=A end k(H)end)end Promise.Each=Promise.each

function Promise.each(list, predicate)
	assert(type(list) == "table", string.format(ERROR_NON_LIST, "Promise.each"))
	assert(type(predicate) == "function", string.format(ERROR_NON_FUNCTION, "Promise.each"))

	return Promise._new(debug.traceback(nil, 2), function(resolve, reject, onCancel)
		local results = {}
		local promisesToCancel = {}

		local cancelled = false

		local function cancel()
			for _, promiseToCancel in ipairs(promisesToCancel) do
				promiseToCancel:cancel()
			end
		end

		onCancel(function()
			cancelled = true

			cancel()
		end)

		-- We need to preprocess the list of values and look for Promises.
		-- If we find some, we must register our andThen calls now, so that those Promises have a consumer
		-- from us registered. If we don't do this, those Promises might get cancelled by something else
		-- before we get to them in the series because it's not possible to tell that we plan to use it
		-- unless we indicate it here.

		local preprocessedList = {}

		for index, value in ipairs(list) do
			if Promise.is(value) then
				if value:getStatus() == Promise.Status.Cancelled then
					cancel()
					return reject(Error.new({
						error = "Promise is cancelled",
						kind = Error.Kind.AlreadyCancelled,
						context = string.format(
							"The Promise that was part of the array at index %d passed into Promise.each was already cancelled when Promise.each began.\n\nThat Promise was created at:\n\n%s",
							index,
							value._source
						),
					}))
				elseif value:getStatus() == Promise.Status.Rejected then
					cancel()
					return reject(select(2, value:await()))
				end

				-- Chain a new Promise from this one so we only cancel ours
				local ourPromise = value:andThen(function(...)
					return ...
				end)

				table.insert(promisesToCancel, ourPromise)
				preprocessedList[index] = ourPromise
			else
				preprocessedList[index] = value
			end
		end

		for index, value in ipairs(preprocessedList) do
			if Promise.is(value) then
				local success
				success, value = value:await()

				if not success then
					cancel()
					return reject(value)
				end
			end

			if cancelled then
				return
			end

			local predicatePromise = Promise.resolve(predicate(value, index))

			table.insert(promisesToCancel, predicatePromise)

			local success, result = predicatePromise:await()

			if not success then
				cancel()
				return reject(result)
			end

			results[index] = result
		end

		resolve(results)
	end)
end
Promise.Each = Promise.each
