about summary refs log tree commit diff stats
path: root/src/io
diff options
context:
space:
mode:
authorbptato <nincsnevem662@gmail.com>2024-05-08 18:39:27 +0200
committerbptato <nincsnevem662@gmail.com>2024-05-08 18:39:27 +0200
commit86f4c56507bc94d03e7d94be6ede884b9e7b5358 (patch)
tree929ce32ada67e8b1d57787d8e6d038fa603fc31e /src/io
parent5c891488423aa7ccbef2fb4332ff6cb4e3c05154 (diff)
downloadchawan-86f4c56507bc94d03e7d94be6ede884b9e7b5358.tar.gz
js: refactor
* prefix to-be-separated modules with js
* remove dynstreams dependency
* untangle from EmptyPromise
* move typeptr into tojs
Diffstat (limited to 'src/io')
-rw-r--r--src/io/promise.nim103
-rw-r--r--src/io/urlfilter.nim2
2 files changed, 100 insertions, 5 deletions
diff --git a/src/io/promise.nim b/src/io/promise.nim
index c675233f..6e57791b 100644
--- a/src/io/promise.nim
+++ b/src/io/promise.nim
@@ -1,10 +1,16 @@
 import std/tables
 
+import bindings/quickjs
+import js/jserror
+import js/javascript
+import js/jsutils
+import js/jsopaque
+import js/tojs
 import types/opt
 
 type
-  PromiseState* = enum
-    PROMISE_PENDING, PROMISE_FULFILLED, PROMISE_REJECTED
+  PromiseState = enum
+    psPending, psFulfilled, psRejected
 
   EmptyPromise* = ref object of RootObj
     cb: (proc())
@@ -47,7 +53,7 @@ proc resolve*(promise: EmptyPromise) =
     if promise.cb != nil:
       promise.cb()
     promise.cb = nil
-    promise.state = PROMISE_FULFILLED
+    promise.state = psFulfilled
     promise = promise.next
     if promise == nil:
       break
@@ -77,7 +83,7 @@ func empty*(map: PromiseMap): bool =
 proc then*(promise: EmptyPromise; cb: (proc())): EmptyPromise {.discardable.} =
   promise.cb = cb
   promise.next = EmptyPromise()
-  if promise.state == PROMISE_FULFILLED:
+  if promise.state == psFulfilled:
     promise.resolve()
   return promise.next
 
@@ -171,3 +177,92 @@ proc all*(promises: seq[EmptyPromise]): EmptyPromise =
   if promises.len == 0:
     res.resolve()
   return res
+
+# * Promise is converted to a JS promise which will be resolved when the Nim
+#   promise is resolved.
+
+proc promiseThenCallback(ctx: JSContext; this_val: JSValue; argc: cint;
+    argv: ptr UncheckedArray[JSValue]; magic: cint;
+    func_data: ptr UncheckedArray[JSValue]): JSValue {.cdecl.} =
+  let fun = func_data[0]
+  let op = JS_GetOpaque(fun, JS_GetClassID(fun))
+  if op != nil:
+    let p = cast[EmptyPromise](op)
+    p.resolve()
+    GC_unref(p)
+    JS_SetOpaque(fun, nil)
+  return JS_UNDEFINED
+
+proc fromJSEmptyPromise*(ctx: JSContext; val: JSValue): JSResult[EmptyPromise] =
+  if not JS_IsObject(val):
+    return err(newTypeError("Value is not an object"))
+  var p = EmptyPromise()
+  GC_ref(p)
+  let tmp = JS_NewObject(ctx)
+  JS_SetOpaque(tmp, cast[pointer](p))
+  let fun = JS_NewCFunctionData(ctx, promiseThenCallback, 0, 0, 1,
+    tmp.toJSValueArray())
+  JS_FreeValue(ctx, tmp)
+  let res = JS_Invoke(ctx, val, ctx.getOpaque().strRefs[jstThen], 1,
+    fun.toJSValueArray())
+  JS_FreeValue(ctx, fun)
+  if JS_IsException(res):
+    JS_FreeValue(ctx, res)
+    return err()
+  JS_FreeValue(ctx, res)
+  return ok(p)
+
+proc toJS*(ctx: JSContext; promise: EmptyPromise): JSValue =
+  var resolving_funcs: array[2, JSValue]
+  let jsPromise = JS_NewPromiseCapability(ctx, resolving_funcs.toJSValueArray())
+  if JS_IsException(jsPromise):
+    return JS_EXCEPTION
+  promise.then(proc() =
+    let res = JS_Call(ctx, resolving_funcs[0], JS_UNDEFINED, 0, nil)
+    JS_FreeValue(ctx, res)
+    JS_FreeValue(ctx, resolving_funcs[0])
+    JS_FreeValue(ctx, resolving_funcs[1]))
+  return jsPromise
+
+proc toJS*[T](ctx: JSContext; promise: Promise[T]): JSValue =
+  var resolving_funcs: array[2, JSValue]
+  let jsPromise = JS_NewPromiseCapability(ctx, resolving_funcs.toJSValueArray())
+  if JS_IsException(jsPromise):
+    return JS_EXCEPTION
+  promise.then(proc(x: T) =
+    let x = toJS(ctx, x)
+    let res = JS_Call(ctx, resolving_funcs[0], JS_UNDEFINED, 1,
+      x.toJSValueArray())
+    JS_FreeValue(ctx, res)
+    JS_FreeValue(ctx, x)
+    JS_FreeValue(ctx, resolving_funcs[0])
+    JS_FreeValue(ctx, resolving_funcs[1]))
+  return jsPromise
+
+proc toJS*[T, E](ctx: JSContext; promise: Promise[Result[T, E]]): JSValue =
+  var resolving_funcs: array[2, JSValue]
+  let jsPromise = JS_NewPromiseCapability(ctx, resolving_funcs.toJSValueArray())
+  if JS_IsException(jsPromise):
+    return JS_EXCEPTION
+  promise.then(proc(x: Result[T, E]) =
+    if x.isSome:
+      let x = when T is void:
+        JS_UNDEFINED
+      else:
+        toJS(ctx, x.get)
+      let res = JS_Call(ctx, resolving_funcs[0], JS_UNDEFINED, 1,
+        x.toJSValueArray())
+      JS_FreeValue(ctx, res)
+      JS_FreeValue(ctx, x)
+    else: # err
+      let x = when E is void:
+        JS_UNDEFINED
+      else:
+        toJS(ctx, x.error)
+      let res = JS_Call(ctx, resolving_funcs[1], JS_UNDEFINED, 1,
+        x.toJSValueArray())
+      JS_FreeValue(ctx, res)
+      JS_FreeValue(ctx, x)
+    JS_FreeValue(ctx, resolving_funcs[0])
+    JS_FreeValue(ctx, resolving_funcs[1]))
+  return jsPromise
diff --git a/src/io/urlfilter.nim b/src/io/urlfilter.nim
index 6bbb247c..4d1d2404 100644
--- a/src/io/urlfilter.nim
+++ b/src/io/urlfilter.nim
@@ -1,6 +1,6 @@
 import std/options
 
-import js/regex
+import js/jsregex
 import types/url
 
 #TODO add denyhost/s for blocklists