about summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/html/env.nim14
-rw-r--r--src/js/timeout.nim123
-rw-r--r--src/local/client.nim14
3 files changed, 61 insertions, 90 deletions
diff --git a/src/html/env.nim b/src/html/env.nim
index 0751d12f..6b70c74f 100644
--- a/src/html/env.nim
+++ b/src/html/env.nim
@@ -109,19 +109,19 @@ proc fetch[T: JSRequest|string](window: Window; input: T;
     return ok(promise)
   return ok(window.loader.fetch(input.request))
 
-proc setTimeout[T: JSValue|string](window: Window; handler: T;
-    timeout = 0i32): int32 {.jsfunc.} =
-  return window.timeouts.setTimeout(handler, timeout)
+proc setTimeout(window: Window; handler: JSValue; timeout = 0i32): int32
+    {.jsfunc.} =
+  return window.timeouts.setTimeout(ttTimeout, handler, timeout)
 
-proc setInterval[T: JSValue|string](window: Window; handler: T;
-    interval = 0i32): int32 {.jsfunc.} =
-  return window.timeouts.setInterval(handler, interval)
+proc setInterval(window: Window; handler: JSValue; interval = 0i32): int32
+    {.jsfunc.} =
+  return window.timeouts.setTimeout(ttInterval, handler, interval)
 
 proc clearTimeout(window: Window; id: int32) {.jsfunc.} =
   window.timeouts.clearTimeout(id)
 
 proc clearInterval(window: Window; id: int32) {.jsfunc.} =
-  window.timeouts.clearInterval(id)
+  window.clearTimeout(id)
 
 func console(window: Window): Console {.jsfget.} =
   return window.internalConsole
diff --git a/src/js/timeout.nim b/src/js/timeout.nim
index 519ab8a6..6c4b157f 100644
--- a/src/js/timeout.nim
+++ b/src/js/timeout.nim
@@ -2,20 +2,25 @@ import std/selectors
 import std/tables
 
 import io/dynstream
+import js/console
+import monoucha/fromjs
 import monoucha/javascript
+import types/opt
 
 type
-  TimeoutEntry = tuple
-    handler: (proc())
-    fdi: int
-    tofree: JSValue
+  TimeoutType* = enum
+    ttTimeout = "setTimeout handler"
+    ttInterval = "setInterval handler"
+
+  TimeoutEntry = ref object
+    t: TimeoutType
+    fd: int
+    val: JSValue
 
   TimeoutState* = object
     timeoutid: int32
     timeouts: Table[int32, TimeoutEntry]
-    intervals: Table[int32, TimeoutEntry]
-    timeout_fdis: Table[int, int32]
-    interval_fdis: Table[int, int32]
+    timeoutFds: Table[int, int32]
     selector: Selector[int] #TODO would be better with void...
     jsctx: JSContext
     err: DynStream #TODO shouldn't be needed
@@ -31,88 +36,54 @@ func newTimeoutState*(selector: Selector[int]; jsctx: JSContext; err: DynStream;
   )
 
 func empty*(state: TimeoutState): bool =
-  return state.timeouts.len == 0 and state.intervals.len == 0
-
-#TODO varargs
-proc setTimeout*[T: JSValue|string](state: var TimeoutState; handler: T;
-    timeout = 0i32): int32 =
-  let id = state.timeoutid
-  inc state.timeoutid
-  let fdi = state.selector.registerTimer(max(timeout, 1), true, 0)
-  state.timeout_fdis[fdi] = id
-  when T is string:
-    let evalJSFree = state.evalJSFree
-    state.timeouts[id] = ((proc() =
-      evalJSFree(handler, "setTimeout handler")
-    ), fdi, JS_NULL)
-  else:
-    let fun = JS_DupValue(state.jsctx, handler)
-    let jsctx = state.jsctx
-    let err = state.err
-    state.timeouts[id] = ((proc() =
-      let ret = JS_Call(jsctx, fun, JS_UNDEFINED, 0, nil)
-      if JS_IsException(ret):
-        jsctx.writeException(err)
-      JS_FreeValue(jsctx, ret)
-    ), fdi, fun)
-  return id
+  return state.timeouts.len == 0
 
 proc clearTimeout*(state: var TimeoutState; id: int32) =
   if id in state.timeouts:
-    let timeout = state.timeouts[id]
-    state.selector.unregister(timeout.fdi)
-    JS_FreeValue(state.jsctx, timeout.tofree)
-    state.timeout_fdis.del(timeout.fdi)
+    let entry = state.timeouts[id]
+    state.selector.unregister(entry.fd)
+    JS_FreeValue(state.jsctx, entry.val)
+    state.timeoutFds.del(entry.fd)
     state.timeouts.del(id)
 
-proc clearInterval*(state: var TimeoutState; id: int32) =
-  if id in state.intervals:
-    let interval = state.intervals[id]
-    state.selector.unregister(interval.fdi)
-    JS_FreeValue(state.jsctx, interval.tofree)
-    state.interval_fdis.del(interval.fdi)
-    state.intervals.del(id)
-
 #TODO varargs
-proc setInterval*[T: JSValue|string](state: var TimeoutState; handler: T;
-    interval = 0i32): int32 =
+proc setTimeout*(state: var TimeoutState; t: TimeoutType; handler: JSValue;
+    timeout = 0i32): int32 =
   let id = state.timeoutid
   inc state.timeoutid
-  let fdi = state.selector.registerTimer(max(interval, 1), false, 0)
-  state.interval_fdis[fdi] = id
-  when T is string:
-    let evalJSFree = state.evalJSFree
-    state.intervals[id] = ((proc() =
-      evalJSFree(handler, "setInterval handler")
-    ), fdi, JS_NULL)
-  else:
-    let fun = JS_DupValue(state.jsctx, handler)
-    let jsctx = state.jsctx
-    let err = state.err
-    state.intervals[id] = ((proc() =
-      let ret = JS_Call(jsctx, handler, JS_UNDEFINED, 0, nil)
-      if JS_IsException(ret):
-        jsctx.writeException(err)
-      JS_FreeValue(jsctx, ret)
-    ), fdi, fun)
+  let fd = state.selector.registerTimer(max(timeout, 1), t == ttTimeout, 0)
+  state.timeoutFds[fd] = id
+  state.timeouts[id] = TimeoutEntry(
+    t: t,
+    fd: fd,
+    val: JS_DupValue(state.jsctx, handler)
+  )
   return id
 
+proc runEntry(state: var TimeoutState; entry: TimeoutEntry; name: string) =
+  if JS_IsFunction(state.jsctx, entry.val):
+    let ret = JS_Call(state.jsctx, entry.val, JS_UNDEFINED, 0, nil)
+    if JS_IsException(ret):
+      state.jsctx.writeException(state.err)
+    JS_FreeValue(state.jsctx, ret)
+  else:
+    let s = fromJS[string](state.jsctx, entry.val)
+    if s.isSome:
+      state.evalJSFree(s.get, "setInterval handler")
+
 proc runTimeoutFd*(state: var TimeoutState; fd: int): bool =
-  if fd in state.interval_fdis:
-    state.intervals[state.interval_fdis[fd]].handler()
-    return true
-  elif fd in state.timeout_fdis:
-    let id = state.timeout_fdis[fd]
-    let timeout = state.timeouts[id]
-    timeout.handler()
+  if fd notin state.timeoutFds:
+    return false
+  let id = state.timeoutFds[fd]
+  let entry = state.timeouts[id]
+  state.runEntry(entry, $entry.t)
+  if entry.t == ttTimeout:
     state.clearTimeout(id)
-    return true
-  return false
+  return true
 
 proc clearAll*(state: var TimeoutState) =
   for entry in state.timeouts.values:
-    JS_FreeValue(state.jsctx, entry.tofree)
-  for entry in state.intervals.values:
-    JS_FreeValue(state.jsctx, entry.tofree)
+    state.selector.unregister(entry.fd)
+    JS_FreeValue(state.jsctx, entry.val)
   state.timeouts.clear()
-  state.intervals.clear()
+  state.timeoutFds.clear()
diff --git a/src/local/client.nim b/src/local/client.nim
index a852d8cd..bdb796a7 100644
--- a/src/local/client.nim
+++ b/src/local/client.nim
@@ -360,19 +360,19 @@ proc input(client: Client): EmptyPromise =
     p.resolve()
   return p
 
-proc setTimeout[T: JSValue|string](client: Client; handler: T;
-    timeout = 0i32): int32 {.jsfunc.} =
-  return client.timeouts.setTimeout(handler, timeout)
+proc setTimeout(client: Client; handler: JSValue; timeout = 0i32): int32
+    {.jsfunc.} =
+  return client.timeouts.setTimeout(ttTimeout, handler, timeout)
 
-proc setInterval[T: JSValue|string](client: Client; handler: T;
-    interval = 0i32): int32 {.jsfunc.} =
-  return client.timeouts.setInterval(handler, interval)
+proc setInterval(client: Client; handler: JSValue; interval = 0i32): int32
+    {.jsfunc.} =
+  return client.timeouts.setTimeout(ttInterval, handler, interval)
 
 proc clearTimeout(client: Client; id: int32) {.jsfunc.} =
   client.timeouts.clearTimeout(id)
 
 proc clearInterval(client: Client; id: int32) {.jsfunc.} =
-  client.timeouts.clearInterval(id)
+  client.clearTimeout(id)
 
 let SIGWINCH {.importc, header: "<signal.h>", nodecl.}: cint