Simplify event handling
This commit is contained in:
parent
86b2dfbdab
commit
99fb0a9cff
|
@ -26,9 +26,6 @@ export asyncdispatch.`callback=`
|
|||
|
||||
proc `==`*(x, y: FieldId): bool {.borrow.}
|
||||
|
||||
proc newLit(p: pointer): NimNode = ident"nil"
|
||||
## Hack to make `newLit` work on `Presevere`.
|
||||
|
||||
proc getCurrentFacet*(): Facet {.error.}
|
||||
## Return the current `Facet` for this context.
|
||||
|
||||
|
@ -46,8 +43,8 @@ template sendMessage*(msg: untyped): untyped =
|
|||
mixin getCurrentFacet
|
||||
send(getCurrentFacet(), toPreserve(msg))
|
||||
|
||||
proc callbackForEvent(event: EventKind; pattern, handler: NimNode): NimNode =
|
||||
## Generate a procedure that checks an event kind, unpacks `pattern` match to fit the
|
||||
proc wrapHandler(handler: NimNode): NimNode =
|
||||
## Generate a procedure that unpacks a `pattern` match to fit the
|
||||
## parameters of `handler`, and calls the body of `handler`.
|
||||
# TODO: compile time analysis of pattern to count number of captures
|
||||
handler.expectKind nnkDo
|
||||
|
@ -55,8 +52,7 @@ proc callbackForEvent(event: EventKind; pattern, handler: NimNode): NimNode =
|
|||
formalArgs = handler[3]
|
||||
cbFacetSym = genSym(nskParam, "facet")
|
||||
scriptFacetSym = genSym(nskParam, "facet")
|
||||
eventSym = genSym(nskParam, "event")
|
||||
recSym = genSym(nskParam, "record")
|
||||
recSym = genSym(nskParam, "bindings")
|
||||
var
|
||||
letSection = newNimNode(nnkLetSection, handler)
|
||||
captureCount: int
|
||||
|
@ -101,31 +97,25 @@ proc callbackForEvent(event: EventKind; pattern, handler: NimNode): NimNode =
|
|||
params = [
|
||||
newEmptyNode(),
|
||||
newIdentDefs(cbFacetSym, ident"Facet"),
|
||||
newIdentDefs(eventSym, ident"EventKind"),
|
||||
newIdentDefs(recSym, newNimNode(nnkBracketExpr).add(ident"seq",
|
||||
ident"Preserve")),
|
||||
],
|
||||
body = newStmtList(
|
||||
newIfStmt((cond: infix(eventSym, "==", newLit(event)), body:
|
||||
body =
|
||||
newStmtList(
|
||||
script,
|
||||
newCall("scheduleScript", cbFacetSym, script[0])
|
||||
)))))
|
||||
))
|
||||
# TODO: this proc just checks the event type and then schedules a script,
|
||||
# should the event check be done in skeletons instead?
|
||||
|
||||
proc onEvent(event: EventKind; pattern, handler: NimNode): NimNode =
|
||||
proc onEvent(event: EventKind; pattern, doHandler: NimNode): NimNode =
|
||||
let
|
||||
handler = callbackForEvent(event, pattern, handler)
|
||||
handler = wrapHandler(doHandler)
|
||||
handlerSym = handler[0]
|
||||
result = quote do:
|
||||
`handler`
|
||||
mixin getCurrentFacet
|
||||
discard getCurrentFacet().addEndpoint do (facet: Facet) -> EndpointSpec:
|
||||
let a = `pattern`
|
||||
result.assertion = some(toPreserve(observe(a)))
|
||||
result.analysis = some(analyzeAssertion(a))
|
||||
result.analysis.get.callback = wrap(facet, `handlerSym`)
|
||||
onEvent(getCurrentFacet(), `pattern`, EventKind(`event`), `handlerSym`)
|
||||
|
||||
macro onAsserted*(pattern: Preserve; handler: untyped) =
|
||||
onEvent(addedEvent, pattern, handler)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# SPDX-License-Identifier: ISC
|
||||
|
||||
import ./bags, ./dataflow, ./events, ./skeletons
|
||||
import ./assertions, ./bags, ./dataflow, ./events, ./skeletons
|
||||
import preserves
|
||||
import std/[asyncdispatch, deques, hashes, macros, options, sets, tables]
|
||||
|
||||
|
@ -332,12 +332,6 @@ proc wrap(facet; script: Script[void]): Task[void] =
|
|||
proc task() = facet.invokeScript(script)
|
||||
task
|
||||
|
||||
proc wrap*(facet; cb: proc(facet: Facet; event: EventKind; bindings: seq[Value]) {.gcsafe.}): HandlerCallback =
|
||||
proc wrapper(event: EventKind; bindings: seq[Value]) =
|
||||
facet.invokeScript do (facet: Facet):
|
||||
cb(facet, event, bindings)
|
||||
wrapper
|
||||
|
||||
proc scheduleScript*(facet; prio: Priority; script: Script[void]) =
|
||||
facet.actor.scheduleTask(prio, facet.wrap(script))
|
||||
|
||||
|
@ -573,3 +567,34 @@ template declareField*(facet: Facet; F: untyped; T: typedesc; initial: T): untyp
|
|||
proc getPreserve(f: DistinctField): Preserve {.used.} =
|
||||
facet.actor.dataspace.dataflow.recordObservation(f.id)
|
||||
facet.fields[fieldOff]
|
||||
|
||||
type EventHandler* = proc (facet: Facet; bindings: seq[Value]) {.gcsafe.}
|
||||
|
||||
proc wrap*(facet; onEvent: EventKind; cb: EventHandler): HandlerCallback =
|
||||
proc wrapper(event: EventKind; bindings: seq[Value]) =
|
||||
facet.invokeScript do (facet: Facet):
|
||||
if event == onEvent:
|
||||
facet.scheduleScript do (facet: Facet):
|
||||
cb(facet, bindings)
|
||||
wrapper
|
||||
|
||||
proc onEvent*(facet; pattern: Preserve; event: EventKind; cb: EventHandler) =
|
||||
discard facet.addEndpoint do (facet: Facet) -> EndpointSpec:
|
||||
result.assertion = some(observe(pattern).toPreserve)
|
||||
result.analysis = some(analyzeAssertion(pattern))
|
||||
result.analysis.get.callback = wrap(facet, event, cb)
|
||||
|
||||
proc onAsserted*(facet; pattern: Preserve; cb: EventHandler) =
|
||||
onEvent(facet, pattern, addedEvent, cb)
|
||||
|
||||
proc onRetracted*(facet; pattern: Preserve; cb: EventHandler) =
|
||||
onEvent(facet, pattern, removedEvent, cb)
|
||||
|
||||
proc onMessage*(facet; pattern: Preserve; cb: EventHandler) =
|
||||
onEvent(facet, pattern, messageEvent, cb)
|
||||
|
||||
template stopIf*(facet: Facet; cond: untyped; continuation: Script[void]): untyped =
|
||||
## Stop the current facet if `cond` is true and
|
||||
## invoke `body` after the facet has stopped.
|
||||
discard facet.addDataflow do (facet: Facet):
|
||||
if cond: facet.stop(continuation)
|
||||
|
|
|
@ -27,43 +27,19 @@ proc boot(facet: Facet) =
|
|||
facet.stop do (facet: Facet):
|
||||
echo "terminated box root facet"
|
||||
|
||||
discard facet.addEndpoint do (facet: Facet) -> EndpointSpec:
|
||||
const a = SetBox.init(`?*`)
|
||||
result.analysis = some analyzeAssertion(a)
|
||||
proc cb(facet: Facet; evt: EventKind; vs: seq[Value]) =
|
||||
if evt == messageEvent:
|
||||
facet.scheduleScript do (facet: Facet):
|
||||
value.set(vs[0])
|
||||
echo "box updated value ", vs[0]
|
||||
result.analysis.get.callback = facet.wrap cb
|
||||
const o = observe(SetBox.init(`?*`)).toPreserve
|
||||
result.assertion = some o
|
||||
facet.onMessage(SetBox.init(`?*`)) do (facet: Facet; vs: seq[Value]):
|
||||
value.set(vs[0])
|
||||
echo "box updated value ", vs[0]
|
||||
|
||||
facet.spawn("client") do (facet: Facet):
|
||||
|
||||
discard facet.addEndpoint do (facet: Facet) -> EndpointSpec:
|
||||
const a = BoxState.init(`?*`)
|
||||
result.analysis = some analyzeAssertion(a)
|
||||
proc cb(facet: Facet; evt: EventKind; vs: seq[Value]) =
|
||||
if evt == addedEvent:
|
||||
facet.scheduleScript do (facet: Facet):
|
||||
let v = SetBox.init(vs[0].int.succ.toPreserve)
|
||||
# echo "client sending ", v
|
||||
facet.send(v)
|
||||
result.analysis.get.callback = facet.wrap cb
|
||||
const o = observe(BoxState.init(`?*`)).toPreserve
|
||||
result.assertion = some o
|
||||
facet.onAsserted(BoxState.init(`?*`)) do (facet: Facet; vs: seq[Value]):
|
||||
let v = SetBox.init(vs[0].int.succ.toPreserve)
|
||||
# echo "client sending ", v
|
||||
facet.send(v)
|
||||
|
||||
discard facet.addEndpoint do (facet: Facet) -> EndpointSpec:
|
||||
const a = BoxState.init(`?_`)
|
||||
result.analysis = some analyzeAssertion(a)
|
||||
proc cb(facet: Facet; evt: EventKind; vs: seq[Value]) =
|
||||
if evt == removedEvent:
|
||||
facet.scheduleScript do (facet: Facet):
|
||||
echo "box gone"
|
||||
result.analysis.get.callback = facet.wrap cb
|
||||
const o = observe(BoxState.init(`?_`)).toPreserve
|
||||
result.assertion = some o
|
||||
facet.onRetracted(BoxState.init(`?_`)) do (facet: Facet; vs: seq[Value]):
|
||||
echo "box gone"
|
||||
|
||||
facet.actor.dataspace.ground.addStopHandler do (_: Dataspace):
|
||||
echo "stopping box-and-client"
|
||||
|
|
Loading…
Reference in New Issue