local e=require(script.Parent.Runtime)local Q={}Q.__index=Q local function U(Q,U)if Q.__resolved then e.__runFutureListener(U,Q.__value)return end table.insert(Q.__listeners,U)end local function P(Q,U)if Q.__resolved then return end Q.__resolved=true Q.__value=U for Q,P in ipairs(Q.__listeners)do e.__runFutureListener(P,U)end end function Q.new()local e=setmetatable({[Q]=true,__resolved=false;__value=nil,__listeners={}},Q)local function U(Q)P(e,Q)end return e,U end function Q.resolved(e)local U,P=Q.new()P(e)return U end function Q.isFuture(e)return type(e)=="\116\097\098\108\101"and e[Q]end function Q.isResolved(e)return e.__resolved end function Q.unwrapOrDie(e)assert(Q.isFuture(e),"\'\115\101\108\102\' \109\117\115\116 \098\101 \097 \070\117\116\117\114\101")if not e.__resolved then error("\070\117\116\117\114\101 \119\097\115 \110\111\116 \114\101\115\111\108\118\101\100\046",2)end return e.__value end function Q.all(e)local P,m=Q.new()local g={}local X=0 for Q,P in ipairs(e)do U(P,function(U)X=X+1 g[Q]=U if X==#e then m(g)end end)end if#e==0 then m(g)end return P end function Q.await(e)assert(Q.isFuture(e),"\'\115\101\108\102\' \109\117\115\116 \098\101 \097 \070\117\116\117\114\101")if e.__resolved then return e.__value end local P=Instance.new("\066\105\110\100\097\098\108\101\069\118\101\110\116")local function m()P:Fire()end U(e,m)P.Event:Wait()return e.__value end function Q.map(P,e)assert(Q.isFuture(P),"\'\115\101\108\102\' \109\117\115\116 \098\101 \097 \070\117\116\117\114\101")local m,g=Q.new()local function X()local Q=e(P.__value)g(Q)end U(P,X)return m end function Q.andThen(P,e)assert(Q.isFuture(P),"\'\115\101\108\102\' \109\117\115\116 \098\101 \097 \070\117\116\117\114\101")local m,g=Q.new()local function X()local U=e(P.__value)assert(Q.isFuture(U))U:map(function(e)g(e)end)end U(P,X)return m end function Q.__tostring(e)if e.__resolved then return("\070\117\116\117\114\101\040\114\101\115\111\108\118\101\100\058 \037\115\041"):format(tostring(e.__value))else return"\070\117\116\117\114\101\040\117\110\114\101\115\111\108\118\101\100\041"end end return Q
local Runtime = require(script.Parent.Runtime)

local Future = {}

Future.__index = Future

local function addListener(future, listener)
	if future.__resolved then
		Runtime.__runFutureListener(listener, future.__value)
		return
	end

	table.insert(future.__listeners, listener)
end

local function resolveFuture(future, value)
	if future.__resolved then
		return
	end

	future.__resolved = true
	future.__value = value

	for _, listener in ipairs(future.__listeners) do
		Runtime.__runFutureListener(listener, value)
	end
end

function Future.new()
	local future = setmetatable({
		[Future] = true,
		__resolved = false,
		__value = nil,
		__listeners = {},
	}, Future)

	local function resolve(value)
		resolveFuture(future, value)
	end

	return future, resolve
end

function Future.resolved(value)
	local future, resolve = Future.new()
	resolve(value)

	return future
end

function Future.isFuture(value)
	return type(value) == "table" and value[Future]
end

function Future:isResolved()
	return self.__resolved
end

function Future:unwrapOrDie()
	assert(Future.isFuture(self), "'self' must be a Future")

	if not self.__resolved then
		error("Future was not resolved.", 2)
	end

	return self.__value
end

function Future.all(futures)
	local outerFuture, resolve = Future.new()
	local result = {}
	local resolvedCount = 0

	for index, future in ipairs(futures) do
		addListener(future, function(value)
			resolvedCount = resolvedCount + 1
			result[index] = value

			if resolvedCount == #futures then
				resolve(result)
			end
		end)
	end

	if #futures == 0 then
		resolve(result)
	end

	return outerFuture
end

function Future:await()
	assert(Future.isFuture(self), "'self' must be a Future")

	if self.__resolved then
		return self.__value
	end

	local bindable = Instance.new("BindableEvent")

	local function listener()
		bindable:Fire()
	end

	addListener(self, listener)

	bindable.Event:Wait()

	return self.__value
end

-- Future<T>
-- param functor: T -> U
-- returns Future<U>
function Future:map(functor)
	assert(Future.isFuture(self), "'self' must be a Future")

	local newFuture, newResolve = Future.new()

	local function listener()
		local newValue = functor(self.__value)
		newResolve(newValue)
	end

	addListener(self, listener)

	return newFuture
end

-- Future<T>
-- param functor: T -> Future<U>
-- returns Future<U>
function Future:andThen(functor)
	assert(Future.isFuture(self), "'self' must be a Future")

	local newFuture, newResolve = Future.new()

	local function listener()
		local chainedFuture = functor(self.__value)

		assert(Future.isFuture(chainedFuture))

		chainedFuture:map(function(value)
			newResolve(value)
		end)
	end

	addListener(self, listener)

	return newFuture
end

function Future:__tostring()
	if self.__resolved then
		return ("Future(resolved: %s)"):format(tostring(self.__value))
	else
		return "Future(unresolved)"
	end
end

return Future