chore(Future): include await system and fallible futures

This commit is contained in:
Erica Marigold 2024-04-14 19:19:08 +05:30
parent b5ba4d9e38
commit 6f02130e51
No known key found for this signature in database
GPG key ID: 2768CC0C23D245D1

View file

@ -4,6 +4,12 @@ local mod = require("../mod")
local Signal = mod.signal local Signal = mod.signal
type Signal<T...> = mod.Signal<T...> type Signal<T...> = mod.Signal<T...>
local result = require("result")
local Result = result.Result
export type Result<T, E> = result.Result<T, E>
local Ok = result.Ok
local Err = result.Err
local Future = {} local Future = {}
export type Status = "initialized" | "running" | "cancelled" | "done" export type Status = "initialized" | "running" | "cancelled" | "done"
export type Future<T> = typeof(Future) & { export type Future<T> = typeof(Future) & {
@ -11,19 +17,14 @@ export type Future<T> = typeof(Future) & {
_ret: T, _ret: T,
_thread: thread, _thread: thread,
_spawnEvt: Signal<()>, _spawnEvt: Signal<()>,
_retEvt: Signal<T, Status>, _retEvt: Signal<T | Result<T, string>, Status>,
_status: Status, _status: Status,
} }
function Future.new<T>(fn: (...any) -> T, args: { any }) local function _constructor<T>(fn: (Signal<()>, Signal<T, Status>) -> (), args: { any })
return setmetatable( return setmetatable(
{ {
_thread = coroutine.create(function(spawnEvt: Signal<()>, retEvt: Signal<T, Status>) _thread = coroutine.create(fn),
spawnEvt:Fire()
local ret = fn(table.unpack(args))
retEvt:Fire(ret, "done")
end),
_spawnEvt = Signal.new(), _spawnEvt = Signal.new(),
_retEvt = Signal.new(), _retEvt = Signal.new(),
@ -35,6 +36,25 @@ function Future.new<T>(fn: (...any) -> T, args: { any })
) )
end end
function Future.new<T>(fn: (...any) -> T, args: { any })
return _constructor(function(spawnEvt: Signal<()>, retEvt: Signal<T, Status>)
spawnEvt:Fire()
local ret = fn(table.unpack(args))
retEvt:Fire(ret, "done")
end, args)
end
function Future.try<T>(fn: (...any) -> T, args: { any })
return _constructor(function(spawnEvt: Signal<()>, retEvt: Signal<Result<T, string>, Status>)
spawnEvt:Fire()
local ok, ret = pcall(fn, table.unpack(args))
local result: Result<T, string> = if ok then Ok(ret) else Err(ret)
retEvt:Fire(result, "done")
end, args)
end
function Future.poll<T>(self: Future<T>): (Status, T) function Future.poll<T>(self: Future<T>): (Status, T)
if self._status == "initialized" then if self._status == "initialized" then
self._retEvt:Connect(function(firedRet, status: Status) self._retEvt:Connect(function(firedRet, status: Status)
@ -68,3 +88,13 @@ function Future.cancel<T>(self: Future<T>)
self._retEvt:Fire(nil :: any, "cancelled") self._retEvt:Fire(nil :: any, "cancelled")
self._status = "cancelled" self._status = "cancelled"
end end
function Future.await<T>(self: Future<T>): T
while true do
local status: Status, ret: T = self:poll()
if status == "done" then
return ret
end
end
end