From d1d1dc575d85c4ec138e2466d26fc44ff8fdf711 Mon Sep 17 00:00:00 2001 From: ivanjermakov Date: Tue, 9 Apr 2024 03:30:56 +0200 Subject: [PATCH] Std: `Future` --- src/std/future.js | 8 +++++ src/std/future.no | 89 ++++++++++++++++++++++++++++++++++++++++++++++ src/std/prelude.no | 1 + 3 files changed, 98 insertions(+) create mode 100644 src/std/future.js create mode 100644 src/std/future.no diff --git a/src/std/future.js b/src/std/future.js new file mode 100644 index 00000000..3896d7b2 --- /dev/null +++ b/src/std/future.js @@ -0,0 +1,8 @@ +/** + * @param {function(): Unit} f + * @param {Int} delay + * @returns {Unit} + */ +function deferFor(f, delay) { + setTimeout(f, delay) +} diff --git a/src/std/future.no b/src/std/future.no new file mode 100644 index 00000000..dc74c417 --- /dev/null +++ b/src/std/future.no @@ -0,0 +1,89 @@ +use std::ref::eqRef + +pub type Future( + f: ||T|: Unit|: Unit, + subscribers: List<|T|: Unit>, + state: FutureState, +) + +// TODO: should be private, but there is a bug with visibility in impls +pub type FutureState { + Created(), + Queued(), + Pending(), + Resolved(value: T), +} + +impl Trace for FutureState {} + +impl Future { + pub fn new(f: ||T|: Unit|: Unit): Self { + Future(f, [], Created()) + } + + pub fn onResolve(self, f: |T|: Unit): Self { + match self.state { + Resolved(value) { + f(value) + return self + } + _ {} + } + self.subscribers.add(f) + self + } + + pub fn spawn(self, runtime: Runtime): Self { + runtime.spawn(self) + } +} + +pub type Runtime( + // TODO: use std::time::Duration + pollingRate: Int, + queue: List>, + pending: List>, +) + +impl Runtime { + pub fn new(): Runtime { + Runtime::withPollingRate(10) + } + + pub fn withPollingRate(pollingRate: Int): Runtime { + Runtime(pollingRate, [], []) + } + + pub fn loop(self): Unit { + while self.queue.count() > 0 { + let next = self.queue.popFront()! + next.state = Pending() + self.pending.add(next) + let _ = (next.f)(|res| { + next.state = Resolved(res) + for s in next.subscribers { + s(res) + } + next.subscribers.clear() + self.pending.popAt(self.pending.iter().position(|e| { eqRef(next, e) })!) + unit + }) + } + if self.queue.count() > 0 || self.pending.count() > 0 { + deferFor(|| { self.loop() }, self.pollingRate) + } + } + + pub fn spawn(self, future: Future): Future { + self.queue.add(future) + future.state = Queued() + future + } +} + +pub fn defer(f: ||: Unit): Unit { + deferFor(f, 0) +} + +pub fn deferFor(f: ||: Unit, delay: Int): Unit + diff --git a/src/std/prelude.no b/src/std/prelude.no index afb14afb..6327980d 100644 --- a/src/std/prelude.no +++ b/src/std/prelude.no @@ -19,4 +19,5 @@ pub use std::{ io::{ println, show::Show, trace::Trace }, option::Option::{ self, Some, None }, result::Result::{ self, Ok, Error }, + future::Future, }