function Promise.each(D,d)assert(type(D)=="\116\097\098\108\101",string.format(ERROR_NON_LIST,"\080\114\111\109\105\115\101\046\101\097\099\104"))assert(type(d)=="\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(c,J,K)local r={}local b={}local f=false local function u()for D,d in ipairs(b)do d:cancel()end end K(function()f=true u()end)local k={}for D,d in ipairs(D)do if Promise.is(d)then if d:getStatus()==Promise.Status.Cancelled then u()return J(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",D,d._source)}))elseif d:getStatus()==Promise.Status.Rejected then u()return J(select(2,d:await()))end local c=d:andThen(function(...)return...end)table.insert(b,c)k[D]=c else k[D]=d end end for D,c in ipairs(k)do if Promise.is(c)then local D D,c=c:await()if not D then u()return J(c)end end if f then return end local K=Promise.resolve(d(c,D))table.insert(b,K)local k,z=K:await()if not k then u()return J(z)end r[D]=z end c(r)end)end

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
