diff --git a/lib/future.luau b/lib/future.luau new file mode 100644 index 0000000..5e7c21b --- /dev/null +++ b/lib/future.luau @@ -0,0 +1,76 @@ +local task = require("@lune/task") + +local mod = require("../mod") +local Signal = mod.signal +type Signal = mod.Signal + +local option = require("option") +type Option = option.Option +local Some = option.Some +local None = option.None + +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, +} + +function Future.new(fn: (...any) -> T, 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), + + _spawnEvt = Signal.new(), + _retEvt = Signal.new(), + _status = "initialized", + } :: Future, + { + __index = Future, + } + ) +end + +function Future.poll(self: Future): (Status, Option) + 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 + + local retOpt = if self._ret == nil then None() else Some(self._ret) + return self._status, retOpt +end + +function Future.cancel(self: Future) + self._retEvt:Fire(nil :: any, "cancelled") + self._status = "cancelled" +end diff --git a/mod.luau b/mod.luau new file mode 100644 index 0000000..f5b03c6 --- /dev/null +++ b/mod.luau @@ -0,0 +1,14 @@ +local luau = require("@lune/luau") +local fs = require("@lune/fs") + +local SIGNAL_PATH = "Packages/_Index/ffrostflame_luausignal@0.2.4/luausignal/src/init.luau" +local _signal = require(SIGNAL_PATH) +export type Signal = _signal.luauSignal +local signal: { + new: () -> Signal, +} = + luau.load('local task = require("@lune/task")\n' .. fs.readFile(SIGNAL_PATH))() + +return { + signal = signal, +} diff --git a/wally.lock b/wally.lock new file mode 100644 index 0000000..b71e14c --- /dev/null +++ b/wally.lock @@ -0,0 +1,13 @@ +# This file is automatically @generated by Wally. +# It is not intended for manual editing. +registry = "test" + +[[package]] +name = "compeydev/rusty-luau" +version = "0.1.0" +dependencies = [["luausignal", "ffrostflame/luausignal@0.2.4"]] + +[[package]] +name = "ffrostflame/luausignal" +version = "0.2.4" +dependencies = [] diff --git a/wally.toml b/wally.toml index 9e001f9..1b5d136 100644 --- a/wally.toml +++ b/wally.toml @@ -8,3 +8,4 @@ exclude = ["tests/**", "examples/**", "**"] include = ["lib/**", "LICENSE.md", "README.md", "wally.toml"] [dependencies] +luausignal = "ffrostflame/luausignal@0.2.4" \ No newline at end of file