diff options
author | bptato <nincsnevem662@gmail.com> | 2022-12-31 02:14:34 +0100 |
---|---|---|
committer | bptato <nincsnevem662@gmail.com> | 2022-12-31 02:14:34 +0100 |
commit | 80b45c0df3f5bbbedb9abfb02fdef608113958e1 (patch) | |
tree | 475cd89df09b4147b8ee6ce9a1ec28954eb6dc30 /src/buffer | |
parent | 310254b09ee2dd3045648848ca9f60f9f1f7c769 (diff) | |
download | chawan-80b45c0df3f5bbbedb9abfb02fdef608113958e1.tar.gz |
Add promise support to JS
Diffstat (limited to 'src/buffer')
-rw-r--r-- | src/buffer/buffer.nim | 119 | ||||
-rw-r--r-- | src/buffer/container.nim | 14 |
2 files changed, 47 insertions, 86 deletions
diff --git a/src/buffer/buffer.nim b/src/buffer/buffer.nim index 17b6e4b8..b4a1c202 100644 --- a/src/buffer/buffer.nim +++ b/src/buffer/buffer.nim @@ -26,6 +26,7 @@ import html/tags import io/loader import io/request import io/posixstream +import io/promise import io/teestream import ips/serialize import ips/serversocket @@ -96,78 +97,36 @@ type savetask: bool hovertext: array[HoverType, string] - # async, but worse - EmptyPromise = ref object of RootObj - cb: (proc()) - next: EmptyPromise + InterfaceOpaque = ref object stream: Stream - - Promise*[T] = ref object of EmptyPromise - res: T + len: int BufferInterface* = ref object - stream*: Stream + map: PromiseMap packetid: int - promises: Table[int, EmptyPromise] + opaque: InterfaceOpaque + stream*: Stream -proc newBufferInterface*(ostream: Stream): BufferInterface = +proc getFromOpaque[T](opaque: pointer, res: var T) = + let opaque = cast[InterfaceOpaque](opaque) + if opaque.len != 0: + opaque.stream.sread(res) + +proc newBufferInterface*(stream: Stream): BufferInterface = + let opaque = InterfaceOpaque(stream: stream) result = BufferInterface( - stream: ostream, - packetid: 1 # ids below 1 are invalid + map: newPromiseMap(cast[pointer](opaque)), + packetid: 1, # ids below 1 are invalid + opaque: opaque, + stream: stream ) -proc fulfill*(iface: BufferInterface, packetid, len: int) = - var promise: EmptyPromise - if iface.promises.pop(packetid, promise): - if promise.stream != nil and promise.cb == nil and len != 0: - var abc = alloc(len) - var x = 0 - while x < len: - x += promise.stream.readData(abc, len) - dealloc(abc) - while promise != nil: - if promise.cb != nil: - promise.cb() - promise = promise.next +proc resolve*(iface: BufferInterface, packetid, len: int) = + iface.opaque.len = len + iface.map.resolve(packetid) proc hasPromises*(iface: BufferInterface): bool = - return iface.promises.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.stream != nil: - promise.stream.sread(promise.res) - cb(promise.res)) - -# Warning: we assume these aren't discarded. -proc then*[T](promise: EmptyPromise, cb: (proc(): Promise[T])): Promise[T] = - 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.cb())) - return next - -proc then*[T, U](promise: Promise[T], cb: (proc(x: T): Promise[U])): Promise[U] = - 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.cb())) - return next + return not iface.map.empty() # get enum identifier of proxy function func getFunId(fun: NimNode): string = @@ -190,9 +149,14 @@ proc buildInterfaceProc(fun: NimNode, funid: string): tuple[fun, name: NimNode] `thisval`.stream.swrite(`thisval`.packetid)) var params2: seq[NimNode] var retval2: NimNode + var addfun: NimNode if retval.kind == nnkEmpty: + addfun = quote do: + `thisval`.map.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) @@ -210,16 +174,13 @@ proc buildInterfaceProc(fun: NimNode, funid: string): tuple[fun, name: NimNode] body.add(quote do: `thisval`.stream.flush()) body.add(quote do: - `thisval`.promises[`thisval`.packetid] = `retval2`(stream: `thisval`.stream) - inc `thisval`.packetid) + let promise = `addfun` + inc `thisval`.packetid + return promise) var pragmas: NimNode if retval.kind == nnkEmpty: - body.add(quote do: - return `thisval`.promises[`thisval`.packetid - 1]) pragmas = newNimNode(nnkPragma).add(ident("discardable")) else: - body.add(quote do: - return `retval2`(`thisval`.promises[`thisval`.packetid - 1])) pragmas = newEmptyNode() return (newProc(name, params2, body, pragmas = pragmas), nup) @@ -659,10 +620,10 @@ proc load*(buffer: Buffer): LoadResult {.proxy, task.} = else: buffer.savetask = true -proc fulfillTask[T](buffer: Buffer, cmd: BufferCommand, res: T) = +proc resolveTask[T](buffer: Buffer, cmd: BufferCommand, res: T) = let packetid = buffer.tasks[cmd] if packetid == 0: - return # no task to fulfill (TODO this is kind of inefficient) + return # no task to resolve (TODO this is kind of inefficient) let len = slen(buffer.tasks[cmd]) + slen(res) buffer.pstream.swrite(len) buffer.pstream.swrite(packetid) @@ -673,7 +634,7 @@ proc fulfillTask[T](buffer: Buffer, cmd: BufferCommand, res: T) = proc onload(buffer: Buffer) = var res: LoadResult = (false, buffer.lines.len, -1) if buffer.loaded: - buffer.fulfillTask(LOAD, res) + buffer.resolveTask(LOAD, res) return let op = buffer.sstream.getPosition() var s = newString(buffer.readbufsize) @@ -691,11 +652,11 @@ proc onload(buffer: Buffer) = res.bytes = buffer.available else: buffer.do_reshape() - buffer.fulfillTask(LOAD, res) + buffer.resolveTask(LOAD, res) except EOFError: res.atend = true buffer.finishLoad() - buffer.fulfillTask(LOAD, res) + buffer.resolveTask(LOAD, res) except ErrorAgain, ErrorWouldBlock: if buffer.readbufsize > 1: buffer.readbufsize = buffer.readbufsize div 2 @@ -858,7 +819,7 @@ proc submitForm(form: HTMLFormElement, submitter: Element): Option[Request] = of FORM_ENCODING_TYPE_TEXT_PLAIN: body = serializePlainTextFormData(entrylist).some mimetype = $enctype - return newRequest(parsedaction, httpmethod, {"Content-Type": mimetype}, body, multipart).some + return newRequest(parsedaction, httpmethod, @{"Content-Type": mimetype}, body, multipart).some template getActionUrl() = return newRequest(parsedaction).some @@ -1099,15 +1060,15 @@ macro bufferDispatcher(funs: static ProxyMap, buffer: Buffer, cmd: BufferCommand rval = ident("retval") stmts.add(quote do: let `rval` = `call`) - var fulfill = newStmtList() + var resolve = newStmtList() if rval == nil: - fulfill.add(quote do: + resolve.add(quote do: let len = slen(`packetid`) buffer.pstream.swrite(len) buffer.pstream.swrite(`packetid`) buffer.pstream.flush()) else: - fulfill.add(quote do: + resolve.add(quote do: let len = slen(`packetid`) + slen(`rval`) buffer.pstream.swrite(len) buffer.pstream.swrite(`packetid`) @@ -1120,9 +1081,9 @@ macro bufferDispatcher(funs: static ProxyMap, buffer: Buffer, cmd: BufferCommand buffer.savetask = false buffer.tasks[BufferCommand.`en`] = `packetid` else: - `fulfill`) + `resolve`) else: - stmts.add(fulfill) + stmts.add(resolve) ofbranch.add(stmts) switch.add(ofbranch) return switch diff --git a/src/buffer/container.nim b/src/buffer/container.nim index 9963f98e..a3406463 100644 --- a/src/buffer/container.nim +++ b/src/buffer/container.nim @@ -11,6 +11,7 @@ when defined(posix): import buffer/buffer import buffer/cell import config/config +import io/promise import io/request import io/window import ips/forkserver @@ -279,7 +280,7 @@ proc setNumLines(container: Container, lines: int, finish = false) = container.triggerEvent(STATUS) proc requestLines*(container: Container, w = container.lineWindow): auto {.discardable.} = - container.iface.getLines(w).then(proc(res: tuple[numLines: int, lines: seq[SimpleFlexibleLine]]) = + return container.iface.getLines(w).then(proc(res: tuple[numLines: int, lines: seq[SimpleFlexibleLine]]) = container.lines.setLen(w.len) container.lineshift = w.a for y in 0 ..< min(res.lines.len, w.len): @@ -724,11 +725,10 @@ proc readSuccess*(container: Container, s: string) = if res.open.isSome: container.triggerEvent(ContainerEvent(t: OPEN, request: res.open.get))) -proc reshape(container: Container, noreq = false) {.jsfunc.} = - container.iface.render().then(proc(lines: int) = - container.setNumLines(lines)) - if not noreq: - container.needslines = true +proc reshape(container: Container): EmptyPromise {.discardable, jsfunc.} = + return container.iface.render().then(proc(lines: int): auto = + container.setNumLines(lines) + return container.requestLines()) proc dupeBuffer*(dispatcher: Dispatcher, container: Container, config: Config, location = none(URL), contenttype = none(string)): Container = let source = BufferSource( @@ -806,7 +806,7 @@ proc handleCommand(container: Container) = var packetid, len: int container.iface.stream.sread(len) container.iface.stream.sread(packetid) - container.iface.fulfill(packetid, len - slen(packetid)) + container.iface.resolve(packetid, len - slen(packetid)) proc setStream*(container: Container, stream: Stream) = container.iface = newBufferInterface(stream) |