local task = require("@lune/task") local mod = require("../mod") local Signal = mod.signal type Signal = mod.Signal local result = require("result") type Result = result.Result local Ok = result.Ok local Err = result.Err local Future = {} export type Status = "initialized" | "running" | "cancelled" | "done" export type Future = typeof(Future) & { _fn: (set: (value: T) -> ()) -> T, _ret: T, _thread: thread, _spawnEvt: Signal<()>, _retEvt: Signal, Status>, _status: Status, } local function _constructor(fn: (Signal<()>, Signal) -> (), args: { any }) return setmetatable( { _thread = coroutine.create(fn), _spawnEvt = Signal.new(), _retEvt = Signal.new(), _status = "initialized", } :: Future, { __index = Future, } ) end function Future.new(fn: (...any) -> T, args: { any }) return _constructor(function(spawnEvt: Signal<()>, retEvt: Signal) spawnEvt:Fire() local ret = fn(table.unpack(args)) retEvt:Fire(ret, "done") end, args) end function Future.try(fn: (...any) -> T, args: { any }) return _constructor(function(spawnEvt: Signal<()>, retEvt: Signal, Status>) spawnEvt:Fire() local ok, ret = pcall(fn, table.unpack(args)) local result: Result = if ok then Ok(ret) else Err(ret) retEvt:Fire(result, "done") end, args) end function Future.poll(self: Future): (Status, T) if self._status == "initialized" then self._retEvt:Connect(function(firedRet, status: Status) self._status = status self._ret = firedRet -- Cleanup coroutine.yield(self._thread) coroutine.close(self._thread) self._spawnEvt:DisconnectAll() self._retEvt:DisconnectAll() end) self._spawnEvt:Connect(function() self._status = "running" end) coroutine.resume(self._thread, self._spawnEvt, self._retEvt) end if self._status == "running" then -- Just wait a bit more for the signal to fire task.wait(0.01) end return self._status, self._ret end function Future.cancel(self: Future) self._retEvt:Fire(nil :: any, "cancelled") self._status = "cancelled" end function Future.await(self: Future): T while true do local status: Status, ret: T = self:poll() if status == "done" then return ret end end end return Future