about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorbptato <nincsnevem662@gmail.com>2024-09-29 14:55:23 +0200
committerbptato <nincsnevem662@gmail.com>2024-09-29 14:58:05 +0200
commit3b7ca109b9009d5875f8cc1bd8c8212fd9abc296 (patch)
tree52f707872c782c49fa442e7e7d989c7748d5821b
parent0035e58925ef005cca0ea0017ce3d54dfca1e72a (diff)
downloadchawan-3b7ca109b9009d5875f8cc1bd8c8212fd9abc296.tar.gz
promise: move PromiseMap to buffer
It's only used there, and there's no reason for every single promise to
carry two pointers to support it.
-rw-r--r--src/io/promise.nim50
-rw-r--r--src/server/buffer.nim73
2 files changed, 51 insertions, 72 deletions
diff --git a/src/io/promise.nim b/src/io/promise.nim
index 8fb55a9b..efb5a0a0 100644
--- a/src/io/promise.nim
+++ b/src/io/promise.nim
@@ -14,38 +14,14 @@ type
   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
+    res*: T
 
 proc newPromise*[T](): Promise[T] =
   return Promise[T]()
 
-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](get: get, opaque: map.opaque)
-  map.tab[id] = promise
-  return promise
-
-proc addEmptyPromise*(map: var PromiseMap; id: int): EmptyPromise =
-  let promise = EmptyPromise(opaque: map.opaque)
-  map.tab[id] = promise
-  return promise
-
 proc resolve*(promise: EmptyPromise) =
   var promise = promise
   while true:
@@ -59,17 +35,9 @@ proc resolve*(promise: EmptyPromise) =
     promise.next = nil
 
 proc resolve*[T](promise: Promise[T]; res: T) =
-  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()
-
 proc newResolvedPromise*(): EmptyPromise =
   let res = EmptyPromise()
   res.resolve()
@@ -80,9 +48,6 @@ proc newResolvedPromise*[T](x: T): Promise[T] =
   res.resolve(x)
   return res
 
-func empty*(map: PromiseMap): bool =
-  map.tab.len == 0
-
 proc then*(promise: EmptyPromise; cb: (proc())): EmptyPromise {.discardable.} =
   promise.cb = cb
   promise.next = EmptyPromise()
@@ -104,11 +69,7 @@ proc then*(promise: EmptyPromise; cb: (proc(): EmptyPromise)): EmptyPromise
 
 proc then*[T](promise: Promise[T]; cb: (proc(x: T))): EmptyPromise
     {.discardable.} =
-  return promise.then(proc() =
-    if promise.get != nil:
-      promise.get(promise.opaque, promise.res)
-      promise.get = nil
-    cb(promise.res))
+  return promise.then(proc() = cb(promise.res))
 
 proc then*[T](promise: EmptyPromise; cb: (proc(): Promise[T])): Promise[T]
     {.discardable.} =
@@ -189,8 +150,8 @@ proc all*(promises: seq[EmptyPromise]): EmptyPromise =
     res.resolve()
   return res
 
-# * Promise is converted to a JS promise which will be resolved when the Nim
-#   promise is resolved.
+# 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;
@@ -279,8 +240,7 @@ proc toJS*[T, E](ctx: JSContext; promise: Promise[Result[T, E]]): JSValue =
         JS_UNDEFINED
       else:
         toJS(ctx, x.error)
-      let res = JS_Call(ctx, resolvingFuncs[1], JS_UNDEFINED, 1,
-        x.toJSValueArray())
+      let res = JS_Call(ctx, resolvingFuncs[1], JS_UNDEFINED, 1, x.toJSValueArray())
       JS_FreeValue(ctx, res)
       JS_FreeValue(ctx, x)
     JS_FreeValue(ctx, resolvingFuncs[0])
diff --git a/src/server/buffer.nim b/src/server/buffer.nim
index 858a737c..c50f5653 100644
--- a/src/server/buffer.nim
+++ b/src/server/buffer.nim
@@ -115,15 +115,11 @@ type
     userstyle: CSSStylesheet
     window: Window
 
-  InterfaceOpaque = ref object
-    stream: SocketStream
-    len: int
-    auxLen: int
-
   BufferInterface* = ref object
-    map: PromiseMap
+    map: seq[tuple[promiseid: int; p: EmptyPromise; get: GetValueProc]]
     packetid: int
-    opaque: InterfaceOpaque
+    len: int
+    auxLen: int
     stream*: BufStream
 
   BufferConfig* = object
@@ -139,20 +135,44 @@ type
     autofocus*: bool
     metaRefresh*: MetaRefresh
 
-proc getFromOpaque[T](opaque: pointer; res: var T) =
-  let opaque = cast[InterfaceOpaque](opaque)
-  if opaque.len != 0:
-    var r = opaque.stream.initReader(opaque.len, opaque.auxLen)
-    r.sread(res)
-    opaque.len = 0
+  GetValueProc = proc(iface: BufferInterface; promise: EmptyPromise) {.nimcall.}
+
+proc getFromStream[T](iface: BufferInterface; promise: EmptyPromise) =
+  if iface.len != 0:
+    let promise = Promise[T](promise)
+    var r = iface.stream.initReader(iface.len, iface.auxLen)
+    r.sread(promise.res)
+    iface.len = 0
+
+proc addPromise*[T](iface: BufferInterface; id: int): Promise[T] =
+  let promise = Promise[T]()
+  iface.map.add((id, promise, getFromStream[T]))
+  return promise
+
+proc addEmptyPromise*(iface: BufferInterface; id: int): EmptyPromise =
+  let promise = EmptyPromise()
+  iface.map.add((id, promise, nil))
+  return promise
+
+func findPromise(iface: BufferInterface; promiseid: int): int =
+  for i in 0 ..< iface.map.len:
+    if iface.map[i].promiseid == promiseid:
+      return i
+  return -1
+
+proc resolve(iface: BufferInterface; promiseid: int) =
+  let i = iface.findPromise(promiseid)
+  if i != -1:
+    let (_, promise, get) = iface.map[i]
+    if get != nil:
+      get(iface, promise)
+    promise.resolve()
+    iface.map.del(i)
 
 proc newBufferInterface*(stream: SocketStream; registerFun: proc(fd: int)):
     BufferInterface =
-  let opaque = InterfaceOpaque(stream: stream)
   return BufferInterface(
-    map: newPromiseMap(cast[pointer](opaque)),
     packetid: 1, # ids below 1 are invalid
-    opaque: opaque,
     stream: newBufStream(stream, registerFun)
   )
 
@@ -172,17 +192,17 @@ proc cloneInterface*(stream: SocketStream; registerFun: proc(fd: int)):
   return iface
 
 proc resolve*(iface: BufferInterface; packetid, len, auxLen: int) =
-  iface.opaque.len = len
-  iface.opaque.auxLen = auxLen
-  iface.map.resolve(packetid)
+  iface.len = len
+  iface.auxLen = auxLen
+  iface.resolve(packetid)
   # Protection against accidentally not exhausting data available to read,
-  # by setting opaque len to 0 in getFromOpaque.
+  # by setting len to 0 in getFromStream.
   # (If this assertion is failing, then it means you then()'ed a promise which
   # should read something from the stream with an empty function.)
-  assert iface.opaque.len == 0
+  assert iface.len == 0
 
 proc hasPromises*(iface: BufferInterface): bool =
-  return not iface.map.empty()
+  return iface.map.len > 0
 
 # get enum identifier of proxy function
 func getFunId(fun: NimNode): string =
@@ -199,18 +219,17 @@ proc buildInterfaceProc(fun: NimNode; funid: string):
   let nup = ident(funid) # add this to enums
   let this2 = newIdentDefs(ident("iface"), ident("BufferInterface"))
   let thisval = this2[0]
-  var params2: seq[NimNode]
+  var params2: seq[NimNode] = @[]
   var retval2: NimNode
   var addfun: NimNode
   if retval.kind == nnkEmpty:
     addfun = quote do:
-      `thisval`.map.addEmptyPromise(`thisval`.packetid)
+      `thisval`.addEmptyPromise(`thisval`.packetid)
     retval2 = ident("EmptyPromise")
   else:
     addfun = quote do:
-      addPromise[`retval`](`thisval`.map, `thisval`.packetid,
-        getFromOpaque[`retval`])
-    retval2 = newNimNode(nnkBracketExpr).add(ident"Promise", retval)
+      addPromise[`retval`](`thisval`, `thisval`.packetid)
+    retval2 = newNimNode(nnkBracketExpr).add(ident("Promise"), retval)
   params2.add(retval2)
   params2.add(this2)
   # flatten args