From 6f02130e516bd3e14ba23f0ce3c12c406c848cb0 Mon Sep 17 00:00:00 2001 From: Erica Marigold Date: Sun, 14 Apr 2024 19:19:08 +0530 Subject: [PATCH] chore(Future): include await system and fallible futures --- lib/future.luau | 46 ++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 38 insertions(+), 8 deletions(-) diff --git a/lib/future.luau b/lib/future.luau index 766c4f4..d7bd8b1 100644 --- a/lib/future.luau +++ b/lib/future.luau @@ -4,6 +4,12 @@ local mod = require("../mod") local Signal = mod.signal type Signal = mod.Signal +local result = require("result") +local Result = result.Result +export 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) & { @@ -11,19 +17,14 @@ export type Future = typeof(Future) & { _ret: T, _thread: thread, _spawnEvt: Signal<()>, - _retEvt: Signal, + _retEvt: Signal, Status>, _status: Status, } -function Future.new(fn: (...any) -> T, args: { any }) +local function _constructor(fn: (Signal<()>, Signal) -> (), args: { any }) return setmetatable( { - _thread = coroutine.create(function(spawnEvt: Signal<()>, retEvt: Signal) - spawnEvt:Fire() - - local ret = fn(table.unpack(args)) - retEvt:Fire(ret, "done") - end), + _thread = coroutine.create(fn), _spawnEvt = Signal.new(), _retEvt = Signal.new(), @@ -35,6 +36,25 @@ function Future.new(fn: (...any) -> T, args: { any }) ) 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) @@ -68,3 +88,13 @@ 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