about summary refs log tree commit diff stats
path: root/src/io
diff options
context:
space:
mode:
authorbptato <nincsnevem662@gmail.com>2022-12-31 02:14:34 +0100
committerbptato <nincsnevem662@gmail.com>2022-12-31 02:14:34 +0100
commit80b45c0df3f5bbbedb9abfb02fdef608113958e1 (patch)
tree475cd89df09b4147b8ee6ce9a1ec28954eb6dc30 /src/io
parent310254b09ee2dd3045648848ca9f60f9f1f7c769 (diff)
downloadchawan-80b45c0df3f5bbbedb9abfb02fdef608113958e1.tar.gz
Add promise support to JS
Diffstat (limited to 'src/io')
-rw-r--r--src/io/promise.nim107
-rw-r--r--src/io/request.nim4
2 files changed, 109 insertions, 2 deletions
diff --git a/src/io/promise.nim b/src/io/promise.nim
new file mode 100644
index 00000000..46beec6f
--- /dev/null
+++ b/src/io/promise.nim
@@ -0,0 +1,107 @@
+import tables
+
+type
+  PromiseState = enum
+    PROMISE_PENDING, PROMISE_FULFILLED, PROMISE_REJECTED
+
+  EmptyPromise* = ref object of RootObj
+    cb: (proc())
+    next: EmptyPromise
+    opaque: pointer
+    state: PromiseState
+
+  Promise*[T] = ref object of EmptyPromise
+    res: T
+    get: GetValueProc[T]
+
+  GetValueProc[T] = (proc(opaque: pointer, res: var T))
+
+  PromiseMap* = object
+    tab: Table[int, EmptyPromise]
+    opaque*: pointer
+
+proc newPromiseMap*(opaque: pointer): PromiseMap =
+  return PromiseMap(
+    opaque: opaque
+  )
+
+proc addPromise*[T](map: var PromiseMap, id: int, get: GetValueProc[T]): Promise[T] =
+  let promise = Promise[T](state: PROMISE_PENDING, get: get, opaque: map.opaque)
+  map.tab[id] = promise
+  return promise
+
+proc addEmptyPromise*(map: var PromiseMap, id: int): EmptyPromise =
+  let promise = EmptyPromise(state: PROMISE_PENDING, opaque: map.opaque)
+  map.tab[id] = promise
+  return promise
+
+proc resolve*(promise: EmptyPromise) =
+  var promise = promise
+  while true:
+    promise.state = PROMISE_FULFILLED
+    if promise.cb != nil:
+      promise.cb()
+    promise = promise.next
+    if promise == nil:
+      break
+
+proc resolve*[T](promise: Promise[T], res: T) =
+  if promise.cb != nil:
+    if promise.get != nil:
+      promise.get(promise.opaque, promise.res)
+      promise.get = nil
+    promise.res = res
+    promise.resolve()
+
+proc resolve*(map: var PromiseMap, promiseid: int) =
+  var promise: EmptyPromise
+  if map.tab.pop(promiseid, promise):
+    promise.resolve()
+
+func empty*(map: PromiseMap): bool =
+  map.tab.len == 0
+
+proc then*(promise: EmptyPromise, cb: (proc())): EmptyPromise {.discardable.} =
+  if promise == nil: return
+  promise.cb = cb
+  promise.next = EmptyPromise()
+  return promise.next
+
+proc then*[T](promise: Promise[T], cb: (proc(x: T))): EmptyPromise {.discardable.} =
+  if promise == nil: return
+  return promise.then(proc() =
+    if promise.get != nil:
+      promise.get(promise.opaque, promise.res)
+    cb(promise.res))
+
+proc then*[T](promise: EmptyPromise, cb: (proc(): Promise[T])): Promise[T] {.discardable.} =
+  if promise == nil: return
+  let next = Promise[T]()
+  promise.then(proc() =
+    let p2 = cb()
+    if p2 != nil:
+      p2.then(proc(x: T) =
+        next.res = x
+        next.resolve()))
+  return next
+
+proc then*[T](promise: Promise[T], cb: (proc(x: T): EmptyPromise)): EmptyPromise {.discardable.} =
+  if promise == nil: return
+  let next = EmptyPromise()
+  promise.then(proc(x: T) =
+    let p2 = cb(x)
+    if p2 != nil:
+      p2.then(proc() =
+        next.resolve()))
+  return next
+
+proc then*[T, U](promise: Promise[T], cb: (proc(x: T): Promise[U])): Promise[U] {.discardable.} =
+  if promise == nil: return
+  let next = Promise[U]()
+  promise.then(proc(x: T) =
+    let p2 = cb(x)
+    if p2 != nil:
+      p2.then(proc(y: U) =
+        next.res = y
+        next.resolve()))
+  return next
diff --git a/src/io/request.nim b/src/io/request.nim
index d15696fe..79ba7c0d 100644
--- a/src/io/request.nim
+++ b/src/io/request.nim
@@ -163,8 +163,8 @@ func newRequest*(url: URL, httpmethod = HTTP_GET, headers = newHeaderList(),
     destination: destination
   )
 
-func newRequest*(url: URL, httpmethod = HTTP_GET, headers: openarray[(string, string)] = [],
-                 body = none(string), multipart = none(MimeData), mode = RequestMode.NO_CORS): Request =
+func newRequest*(url: URL, httpmethod = HTTP_GET, headers: seq[(string, string)] = @[],
+                 body = none(string), multipart = none(MimeData), mode = RequestMode.NO_CORS): Request {.jsctor.} =
   let hl = newHeaderList()
   for pair in headers:
     let (k, v) = pair