Syndicate with caps
This commit is contained in:
parent
8447822243
commit
77a9ea380f
|
@ -1 +1 @@
|
||||||
Subproject commit 1c4214537b4ed9b577bca3770baea3cb38ad0754
|
Subproject commit 29d7352a23be733a9892a55eb1503b3aaed5ab12
|
|
@ -2,9 +2,14 @@
|
||||||
# SPDX-License-Identifier: Unlicense
|
# SPDX-License-Identifier: Unlicense
|
||||||
|
|
||||||
import std/[asyncdispatch, macros, options]
|
import std/[asyncdispatch, macros, options]
|
||||||
import preserves, preserves/records
|
import preserves
|
||||||
|
|
||||||
|
import syndicate/[actors]
|
||||||
|
|
||||||
|
#[
|
||||||
import syndicate/[assertions, dataspaces, events, skeletons]
|
import syndicate/[assertions, dataspaces, events, skeletons]
|
||||||
|
|
||||||
|
|
||||||
export preserves.fromPreserve
|
export preserves.fromPreserve
|
||||||
export assertions.Observe
|
export assertions.Observe
|
||||||
export dataspaces.Facet
|
export dataspaces.Facet
|
||||||
|
@ -226,3 +231,9 @@ macro `?`*(x: untyped): untyped =
|
||||||
quote: toPreserve(Discard())
|
quote: toPreserve(Discard())
|
||||||
else:
|
else:
|
||||||
quote: toPreserve(Capture())
|
quote: toPreserve(Capture())
|
||||||
|
]#
|
||||||
|
|
||||||
|
proc startActorSystem*(name: string; bootProc: TurnAction): Future[void] =
|
||||||
|
# from python
|
||||||
|
let actor = newActor(name, bootProc)
|
||||||
|
result = actor.future
|
||||||
|
|
|
@ -0,0 +1,486 @@
|
||||||
|
# SPDX-FileCopyrightText: ☭ 2021 Emery Hemingway
|
||||||
|
# SPDX-License-Identifier: Unlicense
|
||||||
|
|
||||||
|
import std/[asyncdispatch, deques, hashes, monotimes, options, sets, tables, times]
|
||||||
|
import preserves, preserves/parse
|
||||||
|
import ../syndicate/protocols/[protocol, sturdy]
|
||||||
|
|
||||||
|
# proc `==`*(x, y: Handle): bool {.borrow.}
|
||||||
|
|
||||||
|
template generateIdType(T: untyped) =
|
||||||
|
type T* = distinct Natural
|
||||||
|
proc `==`*(x, y: T): bool {.borrow.}
|
||||||
|
proc `$`*(id: T): string {.borrow.}
|
||||||
|
|
||||||
|
generateIdType(ActorId)
|
||||||
|
generateIdType(FacetId)
|
||||||
|
generateIdType(EndpointId)
|
||||||
|
generateIdType(FieldId)
|
||||||
|
generateIdType(TurnId)
|
||||||
|
|
||||||
|
#[
|
||||||
|
proc genId(T: type): T =
|
||||||
|
getMonotime().ticks.T
|
||||||
|
]#
|
||||||
|
|
||||||
|
type
|
||||||
|
Attenuation = sturdy.Attenuation[Ref]
|
||||||
|
Oid = sturdy.Oid
|
||||||
|
Assertion* = protocol.Assertion[Ref]
|
||||||
|
Caveat = sturdy.Caveat[Ref]
|
||||||
|
Rewrite = sturdy.Rewrite[Ref]
|
||||||
|
|
||||||
|
Entity* = ref object of RootObj
|
||||||
|
oid*: Oid # oid is how Entities are identified over the wire
|
||||||
|
|
||||||
|
Ref* {.unpreservable.} = ref object # TODO: rename
|
||||||
|
relay*: Facet
|
||||||
|
target*: Entity
|
||||||
|
attenuation*: Attenuation
|
||||||
|
|
||||||
|
OutboundAssertion = ref object
|
||||||
|
handle: Handle
|
||||||
|
peer: Ref
|
||||||
|
established: bool
|
||||||
|
OutboundTable = Table[Handle, OutboundAssertion]
|
||||||
|
|
||||||
|
Actor = ref object
|
||||||
|
future: Future[void]
|
||||||
|
name: string
|
||||||
|
id: ActorId
|
||||||
|
handleAllocator: Handle
|
||||||
|
root: Facet
|
||||||
|
exitReason: ref Exception
|
||||||
|
exitHooks: seq[TurnAction]
|
||||||
|
exiting: bool
|
||||||
|
|
||||||
|
TurnAction* = proc (t: var Turn) {.gcsafe.}
|
||||||
|
|
||||||
|
Queues = TableRef[Facet, seq[TurnAction]]
|
||||||
|
|
||||||
|
Turn* = object # an object that should remain on the stack
|
||||||
|
id: TurnId
|
||||||
|
activeFacet*: Facet
|
||||||
|
queues: Queues # a ref object that can outlive Turn
|
||||||
|
|
||||||
|
ParentFacet = Option[Facet]
|
||||||
|
|
||||||
|
Facet* = ref FacetObj
|
||||||
|
FacetObj = object
|
||||||
|
id: FacetId
|
||||||
|
actor*: Actor
|
||||||
|
parent: ParentFacet
|
||||||
|
children: HashSet[Facet]
|
||||||
|
outbound: OutboundTable
|
||||||
|
shutdownActions: seq[TurnAction]
|
||||||
|
inertCheckPreventers: int
|
||||||
|
isAlive: bool
|
||||||
|
|
||||||
|
using
|
||||||
|
actor: Actor
|
||||||
|
facet: Facet
|
||||||
|
turn: var Turn
|
||||||
|
action: TurnAction
|
||||||
|
|
||||||
|
method publish(e: Entity; turn: var Turn; v: Assertion; h: Handle) {.base.} =
|
||||||
|
raiseAssert "Entity does not implement publish"
|
||||||
|
|
||||||
|
method retract(e: Entity; turn: var Turn; h: Handle) {.base.} =
|
||||||
|
raiseAssert "Entity does not implement retract"
|
||||||
|
|
||||||
|
method message(e: Entity; turn: var Turn; v: Assertion) {.base.} =
|
||||||
|
raiseAssert "Entity does not implement message"
|
||||||
|
|
||||||
|
method sync(e: Entity; turn: var Turn; peer: Ref) {.base.} =
|
||||||
|
raiseAssert "Entity does not implement sync"
|
||||||
|
|
||||||
|
proc labels(f: Facet): string =
|
||||||
|
proc catLabels(f: Facet; labels: var string) =
|
||||||
|
labels.add ':'
|
||||||
|
if f.parent.isSome:
|
||||||
|
catLabels(f.parent.get, labels)
|
||||||
|
labels.add ':'
|
||||||
|
labels.add $f.id
|
||||||
|
result.add f.actor.name
|
||||||
|
catLabels(f, result)
|
||||||
|
|
||||||
|
proc `$`*(f: Facet): string =
|
||||||
|
"<Facet:" & f.labels & ">"
|
||||||
|
|
||||||
|
proc `$`*(r: Ref): string =
|
||||||
|
"<Ref:" & r.relay.labels & ">"
|
||||||
|
|
||||||
|
proc `$`*(actor: Actor): string =
|
||||||
|
"<Actor:" & actor.name & ">" # TODO: ambigous
|
||||||
|
|
||||||
|
proc attenuate(r: Ref; a: Attenuation): Ref =
|
||||||
|
if a.len == 0: result = r
|
||||||
|
else: result = Ref(
|
||||||
|
relay: r.relay,
|
||||||
|
target: r.target,
|
||||||
|
attenuation: a & r.attenuation)
|
||||||
|
|
||||||
|
proc hash*(facet): Hash =
|
||||||
|
facet.id.hash
|
||||||
|
|
||||||
|
proc hash*(r: Ref): Hash =
|
||||||
|
!$(r.relay.hash !&
|
||||||
|
r.target.unsafeAddr.hash) # !&
|
||||||
|
# r.attenuation.toPreserve.hash)
|
||||||
|
# TODO: really convert for each hash?
|
||||||
|
|
||||||
|
proc nextHandle(facet: Facet): Handle =
|
||||||
|
inc facet.actor.handleAllocator
|
||||||
|
facet.actor.handleAllocator
|
||||||
|
|
||||||
|
proc enqueue(turn: var Turn; target: Facet; action: TurnAction) =
|
||||||
|
if target in turn.queues:
|
||||||
|
turn.queues[target].add action
|
||||||
|
else:
|
||||||
|
turn.queues[target] = @[action]
|
||||||
|
|
||||||
|
type Bindings = Table[Preserve[Ref], Preserve[Ref]]
|
||||||
|
|
||||||
|
proc match(p: Pattern; v: Assertion): Option[Bindings] =
|
||||||
|
proc walk(bindings: var Bindings; p: Pattern; v: Assertion): bool =
|
||||||
|
case p.orKind
|
||||||
|
of PatternKind.Pdiscard: result = true
|
||||||
|
of PatternKind.Patom:
|
||||||
|
result = case p.patom
|
||||||
|
of PAtom.Boolean: v.isBoolean
|
||||||
|
of PAtom.Float: v.isFloat
|
||||||
|
of PAtom.Double: v.isDouble
|
||||||
|
of PAtom.Signedinteger: v.isInteger
|
||||||
|
of PAtom.String: v.isString
|
||||||
|
of PAtom.Bytestring: v.isByteString
|
||||||
|
of PAtom.Symbol: v.isSymbol
|
||||||
|
of PatternKind.Pembedded:
|
||||||
|
result = v.isEmbedded
|
||||||
|
of PatternKind.Pbind:
|
||||||
|
if walk(bindings, p.pbind.pattern, v):
|
||||||
|
bindings[toPreserve(p.pbind.pattern, Ref)] = v
|
||||||
|
result = true
|
||||||
|
of PatternKind.Pand:
|
||||||
|
for pp in p.pand.patterns:
|
||||||
|
result = walk(bindings, pp, v)
|
||||||
|
if not result: break
|
||||||
|
of PatternKind.Pnot:
|
||||||
|
var b: Bindings
|
||||||
|
result = not walk(b, p.pnot.pattern, v)
|
||||||
|
of PatternKind.Lit:
|
||||||
|
result = p.lit.value == v
|
||||||
|
of PatternKind.Pcompound:
|
||||||
|
let
|
||||||
|
ctor = p.pcompound.ctor
|
||||||
|
case ctor.orKind
|
||||||
|
of ConstructorspecKind.Crec:
|
||||||
|
if v.isRecord and
|
||||||
|
ctor.crec.label == v.label and
|
||||||
|
ctor.crec.arity == v.arity:
|
||||||
|
for key, pp in p.pcompound.members:
|
||||||
|
if not key.isInteger:
|
||||||
|
result = false
|
||||||
|
else:
|
||||||
|
result = walk(bindings, pp, v.record[key.int])
|
||||||
|
if not result: break
|
||||||
|
of ConstructorspecKind.Carr:
|
||||||
|
if v.isSequence and ctor.carr.arity == v.sequence.len:
|
||||||
|
for key, pp in p.pcompound.members:
|
||||||
|
result =
|
||||||
|
if not key.isInteger: false
|
||||||
|
else: walk(bindings, pp, v.sequence[key.int])
|
||||||
|
if not result: break
|
||||||
|
of ConstructorspecKind.Cdict:
|
||||||
|
if v.isDictionary:
|
||||||
|
for key, pp in p.pcompound.members:
|
||||||
|
let vv = v[key]
|
||||||
|
result =
|
||||||
|
if vv.isFalse: false
|
||||||
|
else: walk(bindings, pp, vv)
|
||||||
|
if not result: break
|
||||||
|
var b: Bindings
|
||||||
|
if walk(b, p, v): result = some b
|
||||||
|
|
||||||
|
proc instantiate(t: Template; bindings: Bindings): Assertion =
|
||||||
|
proc walk(t: Template): Assertion =
|
||||||
|
case t.orKind
|
||||||
|
of TemplateKind.Tattenuate:
|
||||||
|
let v = walk(t.tattenuate.template)
|
||||||
|
if not v.isEmbedded:
|
||||||
|
raise newException(ValueError, "Attempt to attenuate non-capability: " & $v)
|
||||||
|
result = embed(attenuate(v.embed, t.tattenuate.attenuation))
|
||||||
|
of TemplateKind.Tref:
|
||||||
|
let n = $t.tref.binding
|
||||||
|
try: result = bindings[toPreserve(n, Ref)]
|
||||||
|
except KeyError:
|
||||||
|
raise newException(ValueError, "unbound reference: " & n)
|
||||||
|
of TemplateKind.Lit:
|
||||||
|
result = t.lit.value
|
||||||
|
of TemplateKind.Tcompound:
|
||||||
|
let ctor = t.tcompound.ctor
|
||||||
|
case ctor.orKind
|
||||||
|
of ConstructorspecKind.Crec:
|
||||||
|
result = initRecord(ctor.crec.label, ctor.crec.arity)
|
||||||
|
for key, tt in t.tcompound.members:
|
||||||
|
result.record[key.int] = walk(tt)
|
||||||
|
of ConstructorspecKind.Carr:
|
||||||
|
result = initSequence[Ref](ctor.carr.arity)
|
||||||
|
for key, tt in t.tcompound.members:
|
||||||
|
result.sequence[key.int] = walk(tt)
|
||||||
|
of ConstructorspecKind.Cdict:
|
||||||
|
result = initDictionary[Ref]()
|
||||||
|
for key, tt in t.tcompound.members:
|
||||||
|
result[key] = walk(tt)
|
||||||
|
walk(t)
|
||||||
|
|
||||||
|
proc rewrite(r: Rewrite; v: Assertion): Assertion =
|
||||||
|
let bindings = match(r.pattern, v)
|
||||||
|
if bindings.isSome:
|
||||||
|
result = instantiate(r.template, get bindings)
|
||||||
|
|
||||||
|
proc examineAlternatives(cav: Caveat; v: Assertion): Assertion =
|
||||||
|
case cav.orKind
|
||||||
|
of CaveatKind.`Rewrite`:
|
||||||
|
result = rewrite(cav.rewrite, v)
|
||||||
|
of CaveatKind.`Alts`:
|
||||||
|
for r in cav.alts.alternatives:
|
||||||
|
result = rewrite(r, v)
|
||||||
|
if not result.isFalse: break
|
||||||
|
|
||||||
|
proc runRewrites*(a: Attenuation; v: Assertion): Assertion =
|
||||||
|
result = v
|
||||||
|
for stage in a:
|
||||||
|
result = examineAlternatives(stage, result)
|
||||||
|
if result.isFalse: break
|
||||||
|
|
||||||
|
proc publish(turn: var Turn; r: Ref; v: Assertion; h: Handle) =
|
||||||
|
let a = runRewrites(r.attenuation, v)
|
||||||
|
if not a.isFalse:
|
||||||
|
let e = OutboundAssertion(
|
||||||
|
handle: h, peer: r, established: false)
|
||||||
|
turn.activeFacet.outbound[h] = e
|
||||||
|
enqueue(turn, r.relay) do (turn: var Turn):
|
||||||
|
e.established = true
|
||||||
|
publish(r.target, turn, a, e.handle)
|
||||||
|
|
||||||
|
proc publish*(turn: var Turn; r: Ref; a: Assertion): Handle =
|
||||||
|
result = turn.activeFacet.nextHandle()
|
||||||
|
publish(turn, r, a, result)
|
||||||
|
|
||||||
|
proc publish*[T](turn: var Turn; r: Ref; a: T): Handle =
|
||||||
|
publish(turn, r, toPreserve(a, Ref))
|
||||||
|
|
||||||
|
proc retract(turn: var Turn; e: OutboundAssertion) =
|
||||||
|
enqueue(turn, e.peer.relay) do (turn: var Turn):
|
||||||
|
if e.established:
|
||||||
|
e.established = false
|
||||||
|
e.peer.target.retract(turn, e.handle)
|
||||||
|
|
||||||
|
proc retract*(turn: var Turn; h: Handle) =
|
||||||
|
var e: OutboundAssertion
|
||||||
|
if turn.activeFacet.outbound.pop(h, e):
|
||||||
|
turn.retract(e)
|
||||||
|
|
||||||
|
proc message*(turn: var Turn; r: Ref; v: Assertion) =
|
||||||
|
let a = runRewrites(r.attenuation, v)
|
||||||
|
if not a.isFalse:
|
||||||
|
enqueue(turn, r.relay) do (turn: var Turn):
|
||||||
|
r.target.message(turn, a)
|
||||||
|
|
||||||
|
proc sync(turn: var Turn; e: Entity; peer: Ref) =
|
||||||
|
e.sync(turn, peer)
|
||||||
|
# or turn.message(peer, true) ?
|
||||||
|
|
||||||
|
proc sync*(turn: var Turn; r, peer: Ref) =
|
||||||
|
enqueue(turn, r.relay) do (turn: var Turn):
|
||||||
|
sync(turn, r.target, peer)
|
||||||
|
|
||||||
|
proc replace*[T](turn: var Turn; `ref`: Ref; h: Handle; v: T): Handle =
|
||||||
|
result = publish(turn, `ref`, v)
|
||||||
|
retract(turn, h)
|
||||||
|
|
||||||
|
proc stop*(turn: var Turn) {.gcsafe.}
|
||||||
|
|
||||||
|
proc run*(facet; action: TurnAction; zombieTurn = false) {.gcsafe.}
|
||||||
|
|
||||||
|
proc newFacet(actor; parent: ParentFacet; initialAssertions: OutboundTable): Facet =
|
||||||
|
result = Facet(
|
||||||
|
id: getMonoTime().ticks.FacetId,
|
||||||
|
actor: actor,
|
||||||
|
parent: parent,
|
||||||
|
outbound: initialAssertions,
|
||||||
|
isAlive: true)
|
||||||
|
if parent.isSome: parent.get.children.incl result
|
||||||
|
|
||||||
|
proc newFacet(actor; parent: ParentFacet): Facet =
|
||||||
|
var initialAssertions: OutboundTable
|
||||||
|
newFacet(actor, parent, initialAssertions)
|
||||||
|
|
||||||
|
proc onStop(facet; action) =
|
||||||
|
facet.shutdownActions.add action
|
||||||
|
|
||||||
|
proc isInert(facet): bool =
|
||||||
|
facet.inertCheckPreventers == 0 and facet.children.len == 0 and facet.outbound.len == 0
|
||||||
|
|
||||||
|
proc preventInertCheck*(facet): (proc() {.gcsafe.}) =
|
||||||
|
var armed = true
|
||||||
|
inc facet.inertCheckPreventers
|
||||||
|
proc disarm() =
|
||||||
|
if armed:
|
||||||
|
armed = false
|
||||||
|
dec facet.inertCheckPreventers
|
||||||
|
result = disarm
|
||||||
|
|
||||||
|
proc inFacet(turn: var Turn; facet; act: TurnAction) =
|
||||||
|
## Call an action with a facet using a temporary `Turn`
|
||||||
|
## that shares the `Queues` of the calling `Turn`.
|
||||||
|
var t = Turn(activeFacet: facet, queues: turn.queues)
|
||||||
|
act(t)
|
||||||
|
|
||||||
|
proc terminate(actor; turn; reason: ref Exception) {.gcsafe.}
|
||||||
|
|
||||||
|
proc terminate(facet; turn: var Turn; orderly: bool) {.gcsafe.} =
|
||||||
|
if facet.isAlive:
|
||||||
|
facet.isAlive = false
|
||||||
|
let parent = facet.parent
|
||||||
|
block:
|
||||||
|
var turn = Turn(activeFacet: facet, queues: turn.queues)
|
||||||
|
for child in facet.children:
|
||||||
|
child.terminate(turn, orderly)
|
||||||
|
if orderly:
|
||||||
|
for act in facet.shutdownActions:
|
||||||
|
act(turn)
|
||||||
|
for a in facet.outbound.values: turn.retract(a)
|
||||||
|
if orderly:
|
||||||
|
if parent.isSome:
|
||||||
|
if parent.get.isInert:
|
||||||
|
run(parent.get) do (turn: var Turn):
|
||||||
|
parent.get.terminate(turn, true) # TODO: is this the right turn?
|
||||||
|
else:
|
||||||
|
run(facet.actor.root) do (turn: var Turn):
|
||||||
|
terminate(facet.actor, turn, nil) # TODO: is this the right turn?
|
||||||
|
|
||||||
|
proc stopIfInertAfter(action: TurnAction): TurnAction =
|
||||||
|
proc wrapper(turn: var Turn) =
|
||||||
|
action(turn)
|
||||||
|
enqueue(turn, turn.activeFacet) do (turn: var Turn):
|
||||||
|
if (turn.activeFacet.parent.isSome and
|
||||||
|
(not turn.activeFacet.parent.get.isAlive)) or
|
||||||
|
turn.activeFacet.isInert:
|
||||||
|
stop(turn)
|
||||||
|
wrapper
|
||||||
|
|
||||||
|
proc facet*(turn: var Turn; bootProc: TurnAction): Facet =
|
||||||
|
result =newFacet(turn.activeFacet.actor, some turn.activeFacet)
|
||||||
|
inFacet(turn, result, stopIfInertAfter(bootProc))
|
||||||
|
|
||||||
|
proc newActor(name: string; bootProc: TurnAction; initialAssertions: OutboundTable): Actor =
|
||||||
|
let
|
||||||
|
now = getTime()
|
||||||
|
seed = now.toUnix * 1_000_000_000 + now.nanosecond
|
||||||
|
result = Actor(
|
||||||
|
name: name,
|
||||||
|
id: ActorId(seed))
|
||||||
|
result.root = newFacet(result, none Facet)
|
||||||
|
result.future = newFuture[void]($result)
|
||||||
|
run(
|
||||||
|
newFacet(result, some result.root, initialAssertions),
|
||||||
|
# stopIfInertAfter(bootProc) TODO
|
||||||
|
bootProc)
|
||||||
|
|
||||||
|
proc newActor*(name: string; bootProc: TurnAction): Actor =
|
||||||
|
var initialAssertions: OutboundTable
|
||||||
|
newActor(name, bootProc, initialAssertions)
|
||||||
|
|
||||||
|
proc spawn*(name: string; turn: var Turn; bootProc: TurnAction; initialAssertions = initHashSet[Handle]()) =
|
||||||
|
enqueue(turn, turn.activeFacet) do (turn: var Turn):
|
||||||
|
var newOutBound: Table[Handle, OutboundAssertion]
|
||||||
|
for key in initialAssertions:
|
||||||
|
discard turn.activeFacet.outbound.pop(key, newOutbound[key])
|
||||||
|
callSoon:
|
||||||
|
discard newActor(name, bootProc, newOutBound)
|
||||||
|
|
||||||
|
proc newInertRef*(): Ref =
|
||||||
|
# TODO: really create a new actor? Novy does this only once.
|
||||||
|
let a = newActor("") do (turn: var Turn): turn.stop()
|
||||||
|
Ref(relay: a.root)
|
||||||
|
|
||||||
|
proc atExit*(actor; action) = actor.exitHooks.add action
|
||||||
|
|
||||||
|
proc terminate(actor; turn; reason: ref Exception) =
|
||||||
|
if not actor.exiting:
|
||||||
|
actor.exiting = true
|
||||||
|
actor.exitReason = reason
|
||||||
|
for hook in actor.exitHooks: hook(turn)
|
||||||
|
proc finish(turn: var Turn) =
|
||||||
|
actor.root.terminate(turn, not reason.isNil)
|
||||||
|
if reason.isNil:
|
||||||
|
actor.future.complete()
|
||||||
|
else:
|
||||||
|
actor.future.fail reason
|
||||||
|
callSoon:
|
||||||
|
run(actor.root, finish, true)
|
||||||
|
|
||||||
|
proc terminate(facet; e: ref Exception) =
|
||||||
|
run(facet.actor.root) do (turn: var Turn):
|
||||||
|
facet.actor.terminate(turn, e)
|
||||||
|
|
||||||
|
proc asyncCheck*(turn; fut: FutureBase) =
|
||||||
|
let facet = turn.activeFacet
|
||||||
|
fut.addCallback do ():
|
||||||
|
if fut.failed: terminate(facet, fut.error)
|
||||||
|
|
||||||
|
template tryFacet(facet; body: untyped) =
|
||||||
|
body
|
||||||
|
# TODO
|
||||||
|
#try: body
|
||||||
|
#except: terminate(facet, getCurrentException())
|
||||||
|
|
||||||
|
proc run(queues: Queues) =
|
||||||
|
callSoon:
|
||||||
|
for facet, queue in queues:
|
||||||
|
for action in queue: run(facet, action)
|
||||||
|
|
||||||
|
proc run*(facet; action: TurnAction; zombieTurn = false) =
|
||||||
|
if not zombieTurn:
|
||||||
|
if not facet.actor.exitReason.isNil: return
|
||||||
|
if not facet.isAlive: return
|
||||||
|
# TODO: not Nim idiom
|
||||||
|
tryFacet(facet):
|
||||||
|
var turn = Turn(
|
||||||
|
activeFacet: facet,
|
||||||
|
queues: newTable[Facet, seq[TurnAction]]())
|
||||||
|
action(turn)
|
||||||
|
run(turn.queues)
|
||||||
|
|
||||||
|
proc stop*(turn: var Turn, facet: Facet) =
|
||||||
|
enqueue(turn, facet.parent.get) do (turn: var Turn):
|
||||||
|
facet.terminate(turn, true)
|
||||||
|
|
||||||
|
proc stop*(turn: var Turn) =
|
||||||
|
stop(turn, turn.activeFacet)
|
||||||
|
|
||||||
|
proc stopActor*(turn: var Turn) =
|
||||||
|
let actor = turn.activeFacet.actor
|
||||||
|
enqueue(turn, turn.activeFacet.actor.root) do (turn: var Turn):
|
||||||
|
terminate(actor, turn, nil)
|
||||||
|
|
||||||
|
proc freshen*(turn: var Turn, act: TurnAction) =
|
||||||
|
assert(turn.queues.len == 0, "Attempt to freshen a non-stale Turn")
|
||||||
|
run(turn.activeFacet, act)
|
||||||
|
|
||||||
|
proc newRef*(relay: Facet; e: Entity): Ref =
|
||||||
|
Ref(relay: relay, target: e)
|
||||||
|
|
||||||
|
proc newRef*(turn; e: Entity): Ref =
|
||||||
|
Ref(relay: turn.activeFacet, target: e)
|
||||||
|
|
||||||
|
proc sync*(turn, refer: Ref, cb: proc(t: Turn) {.gcsafe.}) =
|
||||||
|
discard # TODO
|
||||||
|
|
||||||
|
proc log*(f: Facet, args: varargs[string, `$`]) =
|
||||||
|
echo f, args
|
||||||
|
|
||||||
|
proc runActor*(name: string; bootProc: TurnAction): Future[void] =
|
||||||
|
let actor = newActor(name, bootProc)
|
||||||
|
result = actor.future
|
|
@ -1,29 +0,0 @@
|
||||||
# SPDX-FileCopyrightText: ☭ 2021 Emery Hemingway
|
|
||||||
# SPDX-License-Identifier: Unlicense
|
|
||||||
|
|
||||||
import std/options
|
|
||||||
import preserves
|
|
||||||
|
|
||||||
type
|
|
||||||
Discard* {.record: "discard", pure.} = object
|
|
||||||
discard
|
|
||||||
|
|
||||||
Capture* {.record: "capture", pure.} = object
|
|
||||||
_: Discard
|
|
||||||
|
|
||||||
Observe* {.record: "observe", pure.} = object
|
|
||||||
pattern: Preserve
|
|
||||||
|
|
||||||
proc observe*[T](x: T): Preserve =
|
|
||||||
Observe(pattern: x.toPreserve).toPreserve
|
|
||||||
|
|
||||||
proc captureCount*(pattern: Preserve): int =
|
|
||||||
if pattern.preserveTo(Capture).isSome:
|
|
||||||
result = 1
|
|
||||||
else:
|
|
||||||
for e in pattern.items:
|
|
||||||
result.inc captureCount(e)
|
|
||||||
|
|
||||||
when isMainModule:
|
|
||||||
let a = observe(`?*`)
|
|
||||||
assert($toPreserve(a) == "<capture <discard>>")
|
|
|
@ -1,577 +1,104 @@
|
||||||
# SPDX-FileCopyrightText: ☭ 2021 Emery Hemingway
|
# SPDX-FileCopyrightText: ☭ 2021 Emery Hemingway
|
||||||
# SPDX-License-Identifier: Unlicense
|
# SPDX-License-Identifier: Unlicense
|
||||||
|
|
||||||
import ./bags, ./dataflow, ./events, ./skeletons
|
import std/[asyncdispatch, hashes, macros, options, tables]
|
||||||
import preserves
|
import preserves
|
||||||
import std/[asyncdispatch, deques, hashes, macros, options, sets, tables]
|
import ../syndicate/protocols/[dataspace, dataspacePatterns]
|
||||||
|
import ./actors, ./bags
|
||||||
|
|
||||||
export dataflow.defineObservableProperty
|
from ../syndicate/protocols/protocol import Handle
|
||||||
export dataflow.recordObservation
|
|
||||||
export dataflow.recordDamage
|
|
||||||
|
|
||||||
template generateIdType(T: untyped) =
|
|
||||||
type T* = distinct Natural
|
|
||||||
proc `==`*(x, y: T): bool {.borrow.}
|
|
||||||
proc `$`*(id: T): string {.borrow.}
|
|
||||||
|
|
||||||
generateIdType(ActorId)
|
|
||||||
generateIdType(FacetId)
|
|
||||||
generateIdType(EndpointId)
|
|
||||||
generateIdType(FieldId)
|
|
||||||
|
|
||||||
type
|
type
|
||||||
Value* = Preserve
|
Value = Preserve[Ref]
|
||||||
Bag = bags.Bag[Value]
|
Pattern* = dataspacePatterns.Pattern[Ref]
|
||||||
|
Observe = dataspace.Observe[Ref]
|
||||||
Task[T] = proc (): T
|
Turn = actors.Turn
|
||||||
Script[T] = proc (facet: Facet): T
|
|
||||||
ActivationScript* = Script[void]
|
|
||||||
|
|
||||||
ActionKind = enum
|
|
||||||
patchAction, messageAction, spawnAction, quitAction, deferredTurnAction, activationAction
|
|
||||||
|
|
||||||
Action = object
|
|
||||||
impl: proc (action: Action; ds: Dataspace; actor: Option[Actor]) {.gcsafe.}
|
|
||||||
case kind: ActionKind
|
|
||||||
of patchAction:
|
|
||||||
changes: Bag
|
|
||||||
else:
|
|
||||||
discard
|
|
||||||
|
|
||||||
Priority = enum
|
|
||||||
pQueryHigh = 0,
|
|
||||||
pQuery,
|
|
||||||
pQueryHandler,
|
|
||||||
pNormal,
|
|
||||||
pGC,
|
|
||||||
pIdle,
|
|
||||||
len
|
|
||||||
|
|
||||||
Actor = ref object
|
|
||||||
id: ActorId
|
|
||||||
name: string
|
|
||||||
dataspace*: Dataspace
|
|
||||||
rootFacet: ParentFacet
|
|
||||||
pendingTasks: array[Priority.len, Deque[Task[void]]]
|
|
||||||
pendingActions: seq[Action]
|
|
||||||
adhocAssertions: Bag
|
|
||||||
cleanupChanges: Bag
|
|
||||||
parentId: ActorId
|
|
||||||
|
|
||||||
EndpointSpec* = tuple
|
|
||||||
callback: HandlerCallback
|
|
||||||
assertion: Value
|
|
||||||
analysis: Option[Analysis]
|
|
||||||
|
|
||||||
Endpoint = ref object
|
|
||||||
id: EndpointId
|
|
||||||
facet: Facet
|
|
||||||
updateProc: Script[EndpointSpec]
|
|
||||||
spec: EndpointSpec
|
|
||||||
|
|
||||||
Field* = object of RootObj
|
|
||||||
id*: FieldId
|
|
||||||
Fields* = seq[Value]
|
|
||||||
# TODO: compile-time tuples
|
|
||||||
|
|
||||||
Turn = object
|
|
||||||
actions: seq[Action]
|
|
||||||
actor: Option[Actor]
|
|
||||||
|
|
||||||
Dataspace* = ref object
|
|
||||||
ground*: Ground
|
|
||||||
index: Index
|
|
||||||
dataflow*: Graph[Endpoint, FieldId]
|
|
||||||
runnable: seq[Actor]
|
|
||||||
pendingTurns: seq[Turn]
|
|
||||||
actors: Table[ActorId, Actor]
|
|
||||||
activations: seq[ActivationScript]
|
|
||||||
nextId: Natural
|
|
||||||
|
|
||||||
StopHandler = proc (ds: Dataspace) {.gcsafe.}
|
|
||||||
|
|
||||||
Ground = ref object
|
|
||||||
dataspace: Dataspace
|
|
||||||
stopHandlers: seq[StopHandler]
|
|
||||||
future: Future[void]
|
|
||||||
externalTaskCount: int
|
|
||||||
stepScheduled: bool
|
|
||||||
|
|
||||||
ParentFacet = Option[Facet]
|
|
||||||
|
|
||||||
Facet* = ref FacetObj
|
|
||||||
FacetObj = object
|
|
||||||
id: FacetId
|
|
||||||
actor*: Actor
|
|
||||||
parent: ParentFacet
|
|
||||||
endpoints: Table[EndpointId, Endpoint]
|
|
||||||
stopScripts: seq[Script[void]]
|
|
||||||
children: Table[FacetId, Facet]
|
|
||||||
fields*: Fields
|
|
||||||
isLive, inScript: bool
|
|
||||||
|
|
||||||
# FacetImpl[Fields] = ref FacetImplObj[Fields]
|
|
||||||
# FacetImplObj[Fields] {.final.} = object of FacetBaseObj
|
|
||||||
|
|
||||||
using
|
|
||||||
dataspace: Dataspace
|
|
||||||
actor: Actor
|
|
||||||
facet: Facet
|
|
||||||
|
|
||||||
proc hash*(ep: Endpoint): Hash =
|
|
||||||
!$(hash(ep.id) !& hash(ep.facet.id))
|
|
||||||
|
|
||||||
proc generateId*(ds: Dataspace): Natural =
|
|
||||||
# TODO: used by declareField, but should be hidden.
|
|
||||||
inc(ds.nextId)
|
|
||||||
ds.nextId
|
|
||||||
|
|
||||||
proc newActor(ds: Dataspace; name: string; initialAssertions: Value; parentId: ActorId): Actor =
|
|
||||||
assert(initialAssertions.kind == pkSet)
|
|
||||||
result = Actor(
|
|
||||||
id: ds.generateId.ActorId,
|
|
||||||
name: name,
|
|
||||||
dataspace: ds,
|
|
||||||
parentId: parentId)
|
|
||||||
for v in initialAssertions.set:
|
|
||||||
discard result.adhocAssertions.change(v, 1)
|
|
||||||
ds.actors[result.id] = result
|
|
||||||
|
|
||||||
proc applyPatch(ds: Dataspace; actor: Option[Actor]; changes: Bag) =
|
|
||||||
type Pair = tuple[val: Value; count: int]
|
|
||||||
var removals: seq[Pair]
|
|
||||||
for a, count in changes.pairs:
|
|
||||||
if count > 0:
|
|
||||||
# debugEcho "applyPatch +", a
|
|
||||||
discard ds.index.adjustAssertion(a, count)
|
|
||||||
else:
|
|
||||||
removals.add((a, count))
|
|
||||||
actor.map do (ac: Actor):
|
|
||||||
discard ac.cleanupChanges.change(a, -count)
|
|
||||||
for (a, count) in removals:
|
|
||||||
# debugEcho "applyPatch -", a
|
|
||||||
discard ds.index.adjustAssertion(a, count)
|
|
||||||
|
|
||||||
proc initPatch(): Action =
|
|
||||||
proc impl(patch: Action; ds: Dataspace; actor: Option[Actor]) {.gcsafe.} =
|
|
||||||
ds.applyPatch(actor, patch.changes)
|
|
||||||
Action(impl: impl, kind: patchAction)
|
|
||||||
|
|
||||||
proc pendingPatch(actor): var Action =
|
|
||||||
for a in actor.pendingActions.mitems:
|
|
||||||
if a.kind == patchAction: return a
|
|
||||||
actor.pendingActions.add(initPatch())
|
|
||||||
actor.pendingActions[actor.pendingActions.high]
|
|
||||||
|
|
||||||
proc adjust(patch: var Action; v: Value; delta: int) =
|
|
||||||
discard patch.changes.change(v, delta)
|
|
||||||
|
|
||||||
proc assert(actor; a: Value) = actor.pendingPatch.adjust(a, +1)
|
|
||||||
|
|
||||||
proc retract(actor; a: Value) = actor.pendingPatch.adjust(a, -1)
|
|
||||||
|
|
||||||
proc install(ep: Endpoint; spec: EndpointSpec) =
|
|
||||||
ep.spec = spec
|
|
||||||
if not ep.spec.assertion.isFalse:
|
|
||||||
ep.facet.actor.assert(ep.spec.assertion)
|
|
||||||
ep.spec.analysis.map do (a: Analysis):
|
|
||||||
assert(not ep.spec.callback.isNil)
|
|
||||||
ep.facet.actor.dataspace.index.addHandler(a, ep.spec.callback)
|
|
||||||
|
|
||||||
proc isRunnable(actor): bool =
|
|
||||||
for tasks in actor.pendingTasks:
|
|
||||||
if tasks.len > 0: return true
|
|
||||||
|
|
||||||
proc scheduleTask(actor; prio: Priority; task: Task[void]) =
|
|
||||||
if not actor.isRunnable:
|
|
||||||
actor.dataspace.runnable.add(actor)
|
|
||||||
actor.pendingTasks[prio].addLast(task)
|
|
||||||
|
|
||||||
proc scheduleTask(actor; task: Task[void]) =
|
|
||||||
scheduleTask(actor, pNormal, task)
|
|
||||||
|
|
||||||
proc abandonQueuedWork(actor) =
|
|
||||||
reset actor.pendingActions
|
|
||||||
for q in actor.pendingTasks.mitems: clear(q)
|
|
||||||
|
|
||||||
proc uninstall(ep: Endpoint; emitPatches: bool) =
|
|
||||||
if emitPatches:
|
|
||||||
if not ep.spec.assertion.isFalse:
|
|
||||||
ep.facet.actor.retract(ep.spec.assertion)
|
|
||||||
ep.spec.analysis.map do (a: Analysis):
|
|
||||||
assert(not ep.spec.callback.isNil)
|
|
||||||
ep.facet.actor.dataspace.index.removeHandler(a, ep.spec.callback)
|
|
||||||
|
|
||||||
proc destroy(ep: Endpoint; emitPatches: bool) =
|
|
||||||
ep.facet.actor.dataspace.dataflow.forgetSubject(ep)
|
|
||||||
ep.uninstall(emitPatches)
|
|
||||||
ep.facet.actor.scheduleTask(pGC) do ():
|
|
||||||
ep.facet.endpoints.del(ep.id)
|
|
||||||
# TODO: cannot remove from ep.facet.endpoints during
|
|
||||||
# its iteration, defering remove is probably unecessary
|
|
||||||
# because the facet is going down.
|
|
||||||
|
|
||||||
proc retractAssertionsAndSubscriptions(facet; emitPatches: bool) =
|
|
||||||
facet.actor.scheduleTask do ():
|
|
||||||
for ep in facet.endpoints.values:
|
|
||||||
ep.destroy(emitPatches)
|
|
||||||
clear(facet.endpoints)
|
|
||||||
|
|
||||||
proc abort(facet; emitPatches: bool) =
|
|
||||||
facet.isLive = false
|
|
||||||
for child in facet.children.values:
|
|
||||||
child.abort(emitPatches)
|
|
||||||
facet.retractAssertionsAndSubscriptions(emitPatches)
|
|
||||||
for s in facet.stopScripts: s(facet)
|
|
||||||
# call stopScripts immediately
|
|
||||||
|
|
||||||
proc enqueueScriptAction(actor; action: Action) =
|
|
||||||
actor.pendingActions.add(action)
|
|
||||||
|
|
||||||
proc enqueueScriptAction(facet; action: Action) =
|
|
||||||
enqueueScriptAction(facet.actor, action)
|
|
||||||
|
|
||||||
proc initQuitAction(): Action =
|
|
||||||
proc impl(action: Action; ds: Dataspace; actor: Option[Actor]) =
|
|
||||||
assert(actor.isSome)
|
|
||||||
ds.applyPatch(actor, actor.get.cleanupChanges)
|
|
||||||
ds.actors.del(actor.get.id)
|
|
||||||
Action(impl: impl, kind: quitAction)
|
|
||||||
|
|
||||||
proc terminate(actor; emitPatches: bool) =
|
|
||||||
if emitPatches:
|
|
||||||
actor.scheduleTask do ():
|
|
||||||
for a in actor.adhocAssertions.keys:
|
|
||||||
actor.retract(a)
|
|
||||||
actor.rootFacet.map do (root: Facet):
|
|
||||||
root.abort(emitPatches)
|
|
||||||
actor.scheduleTask do ():
|
|
||||||
actor.enqueueScriptAction(initQuitAction())
|
|
||||||
|
|
||||||
proc invokeScript(facet; script: Script[void]) =
|
|
||||||
try: script(facet)
|
|
||||||
except:
|
|
||||||
let e = getCurrentException()
|
|
||||||
# TODO: install an error handling callback at the facet?
|
|
||||||
facet.actor.abandonQueuedWork()
|
|
||||||
facet.actor.terminate(false)
|
|
||||||
raise e
|
|
||||||
|
|
||||||
func isInert(facet): bool =
|
|
||||||
facet.endpoints.len == 0 and facet.children.len == 0
|
|
||||||
|
|
||||||
proc terminate(facet) =
|
|
||||||
if facet.isLive:
|
|
||||||
let
|
|
||||||
actor = facet.actor
|
|
||||||
parent = facet.parent
|
|
||||||
if parent.isNone:
|
|
||||||
reset actor.rootFacet
|
|
||||||
facet.isLive = false
|
|
||||||
for child in facet.children.values:
|
|
||||||
child.terminate()
|
|
||||||
reset facet.children
|
|
||||||
actor.scheduleTask do ():
|
|
||||||
facet.invokeScript do (facet: Facet):
|
|
||||||
for s in facet.stopScripts:
|
|
||||||
s(facet)
|
|
||||||
|
|
||||||
facet.retractAssertionsAndSubscriptions(true)
|
|
||||||
actor.scheduleTask(pGC) do ():
|
|
||||||
if parent.isSome:
|
|
||||||
if parent.get.isInert:
|
|
||||||
parent.get.terminate()
|
|
||||||
else:
|
|
||||||
actor.terminate(true)
|
|
||||||
|
|
||||||
template withNonScriptContext(facet; body: untyped) =
|
|
||||||
let inScriptPrev = facet.inScript
|
|
||||||
facet.inScript = false
|
|
||||||
try: body
|
|
||||||
finally: facet.inScript = inScriptPrev
|
|
||||||
|
|
||||||
proc ensureFacetSetup(facet; s: string) =
|
|
||||||
assert(not facet.inScript, "Cannot " & s & " ouside facet setup")
|
|
||||||
|
|
||||||
proc ensureNonFacetSetup(facet; s: string) =
|
|
||||||
assert(facet.inScript, "Cannot " & s & " during facet setup")
|
|
||||||
|
|
||||||
proc wrap(facet; script: Script[void]): Task[void] =
|
|
||||||
proc task() = facet.invokeScript(script)
|
|
||||||
task
|
|
||||||
|
|
||||||
proc scheduleScript*(facet; prio: Priority; script: Script[void]) =
|
|
||||||
facet.actor.scheduleTask(prio, facet.wrap(script))
|
|
||||||
|
|
||||||
proc scheduleScript*(facet; script: Script[void]) =
|
|
||||||
facet.actor.scheduleTask(pNormal, facet.wrap(script))
|
|
||||||
|
|
||||||
proc addStartScript*(facet; s: Script[void]) =
|
|
||||||
facet.ensureFacetSetup("onStart")
|
|
||||||
facet.scheduleScript(pNormal, s)
|
|
||||||
|
|
||||||
proc addStopScript*(facet; s: Script[void]) =
|
|
||||||
facet.stopScripts.add(s)
|
|
||||||
|
|
||||||
proc addFacet(actor; parentFacet: Option[Facet]; bootScript: Script[void]; checkInScript = false) =
|
|
||||||
if checkInScript and parentFacet.isSome:
|
|
||||||
assert parentFacet.get.inScript
|
|
||||||
let f = Facet(
|
|
||||||
id: actor.dataspace.generateId.FacetId,
|
|
||||||
actor: actor,
|
|
||||||
parent: parentFacet,
|
|
||||||
isLive: true,
|
|
||||||
inScript: true)
|
|
||||||
if parentFacet.isSome:
|
|
||||||
parentFacet.get.children[f.id] = f
|
|
||||||
f.fields = parentFacet.get.fields
|
|
||||||
# inherit scope by copying fields of the parent
|
|
||||||
else:
|
|
||||||
actor.rootFacet = some f
|
|
||||||
f.invokeScript do (facet: Facet):
|
|
||||||
facet.withNonScriptContext:
|
|
||||||
bootScript(facet)
|
|
||||||
actor.scheduleTask do ():
|
|
||||||
if ((parentFacet.isSome) and (not parentFacet.get.isLive)) or f.isInert:
|
|
||||||
f.terminate()
|
|
||||||
|
|
||||||
proc addChildFacet*(facet; bootProc: Script[void]) =
|
|
||||||
facet.actor.addFacet(some facet, bootProc, true)
|
|
||||||
|
|
||||||
proc deliverMessage(ds: Dataspace; msg: Value; ac: Option[Actor]) =
|
|
||||||
ds.index.deliverMessage(msg)
|
|
||||||
|
|
||||||
proc adhocRetract(actor; a: Value) =
|
|
||||||
if actor.adhocAssertions.change(a, -1, true) == cdPresentToAbsent:
|
|
||||||
actor.retract(a)
|
|
||||||
|
|
||||||
proc refresh(ep: Endpoint) =
|
|
||||||
let newSpec = ep.updateProc(ep.facet)
|
|
||||||
if newSpec.assertion != ep.spec.assertion:
|
|
||||||
ep.uninstall(true)
|
|
||||||
ep.install(newSpec)
|
|
||||||
|
|
||||||
proc refreshAssertions(ds: Dataspace) =
|
|
||||||
ds.dataflow.repairDamage do (ep: Endpoint):
|
|
||||||
let facet = ep.facet
|
|
||||||
assert(facet.isLive)
|
|
||||||
facet.invokeScript do (f: Facet):
|
|
||||||
f.withNonScriptContext:
|
|
||||||
refresh(ep)
|
|
||||||
|
|
||||||
proc addActor(ds: Dataspace; name: string; bootProc: Script[void]; initialAssertions: Value; parent: Option[Actor]) =
|
|
||||||
var parentId: ActorId
|
|
||||||
parent.map do (p: Actor): parentId = p.id
|
|
||||||
let ac = newActor(ds, name, initialAssertions, parentId)
|
|
||||||
ds.applyPatch(some ac, ac.adhocAssertions)
|
|
||||||
ac.addFacet(none Facet) do (systemFacet: Facet):
|
|
||||||
# Root facet is a dummy "system" facet that exists to hold
|
|
||||||
# one-or-more "user" "root" facets.
|
|
||||||
ac.addFacet(some systemFacet, bootProc)
|
|
||||||
# ^ The "true root", user-visible facet.
|
|
||||||
for a in initialAssertions.set:
|
|
||||||
ac.adhocRetract(a)
|
|
||||||
|
|
||||||
proc send*(facet; body: Value) =
|
|
||||||
## Send a message into the dataspace.
|
|
||||||
facet.ensureNonFacetSetup("send")
|
|
||||||
proc impl(_: Action; ds: Dataspace; actor: Option[Actor]) =
|
|
||||||
ds.deliverMessage(body, actor)
|
|
||||||
facet.enqueueScriptAction(Action(impl: impl, kind: messageAction))
|
|
||||||
|
|
||||||
proc initSpawnAction(name: string; bootProc: Script[void], initialAssertions: Value): Action =
|
|
||||||
proc impl(action: Action; ds: Dataspace; actor: Option[Actor]) =
|
|
||||||
ds.addActor(name, bootProc, initialAssertions, actor)
|
|
||||||
Action(impl: impl, kind: spawnAction)
|
|
||||||
|
|
||||||
proc spawn*(facet; name: string; bootProc: Script[void], initialAssertions: Value) =
|
|
||||||
facet.ensureNonFacetSetup("spawn")
|
|
||||||
facet.enqueueScriptAction(initSpawnAction(name, bootProc, initialAssertions))
|
|
||||||
|
|
||||||
proc spawn*(facet; name: string; bootProc: Script[void]) =
|
|
||||||
spawn(facet, name, bootProc, Value(kind: pkSet))
|
|
||||||
|
|
||||||
#[
|
#[
|
||||||
template spawn*(facet; name: string; fields: untyped; bootProc: Script[void]): untyped =
|
DataspaceEntity = ref object of Entity
|
||||||
type Fields = typeof(fields)
|
assertions: Bag[Assertion]
|
||||||
spawn[Fields](facet, name, bootProc, Value(kind: pkSet))
|
subscriptions: Table[Assertion, TableRef[Ref, TableRef[Assertion, Handle]]]
|
||||||
|
handleMap: Table[Handle, Assertion] # breaks toPreserve(Observe[Ref]())
|
||||||
|
|
||||||
|
method publish(ds: DataspaceEntity; turn: var Turn; rec: Assertion; h: Handle) =
|
||||||
|
if rec.isRecord:
|
||||||
|
ds.handleMap[h] = rec
|
||||||
|
if ds.assertions.change(rec, +1) == cdAbsentToPresent:
|
||||||
|
var obs: Observe
|
||||||
|
if fromPreserve(obs, rec):
|
||||||
|
var seen = newTable[Assertion, Handle]()
|
||||||
|
for prev, count in ds.assertions.pairs:
|
||||||
|
if prev == rec.label:
|
||||||
|
seen[prev] = publish(turn, obs.observer.unembed, prev)
|
||||||
|
var patternSubs = ds.subscriptions.getOrDefault(rec.label)
|
||||||
|
if patternSubs.isNil:
|
||||||
|
patternSubs = newTable[Ref, TableRef[Value, Handle]]()
|
||||||
|
ds.subscriptions[rec.label] = patternSubs
|
||||||
|
patternSubs[obs.observer.unembed] = move seen
|
||||||
|
for peer, seen in ds.subscriptions[rec.label]:
|
||||||
|
if rec notin seen:
|
||||||
|
seen[rec] = publish(turn, peer, rec)
|
||||||
|
|
||||||
|
method retract(ds: DataspaceEntity; turn: var Turn; upstreamHandle: Handle) =
|
||||||
|
let rec = ds.handleMap.getOrDefault(upstreamHandle)
|
||||||
|
if rec.isRecord:
|
||||||
|
ds.handleMap.del upstreamHandle
|
||||||
|
if ds.assertions.change(rec, -1) == cdPresentToAbsent:
|
||||||
|
for peer, seen in ds.subscriptions[rec.label]:
|
||||||
|
var h: Handle
|
||||||
|
if pop(seen, rec, h): retract(turn, h)
|
||||||
|
preserveTo(rec, Observe).map do (obs: Observe):
|
||||||
|
let peerMap = ds.subscriptions[rec.label]
|
||||||
|
peerMap.del(obs.observer.unembed)
|
||||||
|
if peerMap.len == 0:
|
||||||
|
ds.subscriptions.del(rec.label)
|
||||||
|
|
||||||
|
method message(ds: DataspaceEntity; turn: var Turn; msg: Assertion) =
|
||||||
|
if msg.isRecord:
|
||||||
|
for peer, seen in ds.subscriptions[msg.label].pairs:
|
||||||
|
message(turn, peer, msg)
|
||||||
]#
|
]#
|
||||||
|
|
||||||
proc initActivationAction(script: ActivationScript; name: string): Action =
|
type DuringProc* = proc (turn: var Turn; a: Assertion): TurnAction {.gcsafe.}
|
||||||
proc impl(action: Action; ds: Dataspace; actor: Option[Actor]) =
|
|
||||||
for s in ds.activations:
|
|
||||||
if s == script: return
|
|
||||||
ds.activations.add(script)
|
|
||||||
proc boot(root: Facet) =
|
|
||||||
root.addStartScript(script)
|
|
||||||
ds.addActor(name, boot, Value(kind: pkSet), actor)
|
|
||||||
Action(impl: impl, kind: activationAction)
|
|
||||||
|
|
||||||
proc activate(facet; name: string; script: ActivationScript) =
|
type
|
||||||
facet.ensureNonFacetSetup "`activate`"
|
DuringActionKind = enum null, dead, act
|
||||||
facet.enqueueScriptAction(initActivationAction(script, name))
|
DuringAction = object
|
||||||
|
case kind: DuringActionKind
|
||||||
|
of null, dead: discard
|
||||||
|
of act:
|
||||||
|
action: TurnAction
|
||||||
|
|
||||||
proc newDataspace(ground: Ground; name: string; bootProc: ActivationScript): Dataspace =
|
type DuringEntity = ref object of Entity
|
||||||
let turn = Turn(actions: @[initSpawnAction(name, bootProc, Value(kind: pkSet))])
|
assertionMap: Table[Handle, DuringAction]
|
||||||
Dataspace(ground: ground, index: initIndex(), pendingTurns: @[turn])
|
cb: DuringProc
|
||||||
|
|
||||||
proc addEndpoint*(facet; updateScript: Script[EndpointSpec], isDynamic = true) =
|
method publish(de: DuringEntity; turn: var Turn; a: Assertion; h: Handle) =
|
||||||
facet.ensureFacetSetup("addEndpoint")
|
let action = de.cb(turn, a)
|
||||||
let
|
# assert(not action.isNil "should have put in a no-op action")
|
||||||
actor = facet.actor
|
let g = de.assertionMap.getOrDefault h
|
||||||
dataspace = actor.dataspace
|
case g.kind
|
||||||
ep = Endpoint(
|
of null:
|
||||||
id: dataspace.generateId.EndpointId,
|
de.assertionMap[h] = DuringAction(kind: act, action: action)
|
||||||
facet: facet,
|
of dead:
|
||||||
updateProc: updateScript)
|
de.assertionMap.del h
|
||||||
dataspace.dataflow.addSubject(ep)
|
freshen(turn, action)
|
||||||
let
|
of act:
|
||||||
dyn = if isDynamic: some ep else: none Endpoint
|
raiseAssert("during: duplicate handle in publish: " & $h)
|
||||||
initialSpec = dataspace.dataflow.withSubject(dyn) do () -> EndpointSpec:
|
|
||||||
updateScript(facet)
|
|
||||||
assert:
|
|
||||||
(initialSpec.analysis.isNone and initialSpec.callback.isNil) or
|
|
||||||
(initialSpec.analysis.isSome and (not initialSpec.callback.isNil))
|
|
||||||
ep.install(initialSpec)
|
|
||||||
facet.endpoints[ep.id] = ep
|
|
||||||
|
|
||||||
proc addDataflow*(facet; prio: Priority; subjectProc: Script[void]) =
|
method retract(de: DuringEntity; turn: var Turn; h: Handle) =
|
||||||
facet.addEndpoint do (fa: Facet) -> EndpointSpec:
|
let g = de.assertionMap.getOrDefault h
|
||||||
let subjectId = facet.actor.dataspace.dataflow.currentSubjectId
|
case g.kind
|
||||||
facet.scheduleScript(prio) do (fa: Facet):
|
of null:
|
||||||
if facet.isLive:
|
de.assertionMap[h] = DuringAction(kind: dead)
|
||||||
facet.actor.dataspace.dataflow.withSubject(subjectId):
|
of dead:
|
||||||
subjectProc(facet)
|
raiseAssert("during: duplicate handle in retract: " & $h)
|
||||||
|
of act:
|
||||||
|
de.assertionMap.del h
|
||||||
|
g.action(turn)
|
||||||
|
|
||||||
proc addDataflow*(facet; subjectProc: Script[void]) =
|
proc during*(cb: DuringProc): DuringEntity =
|
||||||
addDataflow(facet, pNormal, subjectProc)
|
result = DuringEntity(cb: cb)
|
||||||
|
|
||||||
proc commitActions(dataspace; actor; pending: seq[Action]) =
|
proc observe*(turn: var Turn; ds: Ref; pat: Pattern; e: Entity): Handle =
|
||||||
dataspace.pendingTurns.add(Turn(actor: some actor, actions: pending))
|
publish(turn, ds, Observe(pattern: pat, observer: embed newRef(turn, e)))
|
||||||
|
|
||||||
proc runPendingTask(actor): bool =
|
|
||||||
for deque in actor.pendingTasks.mitems:
|
|
||||||
if deque.len > 0:
|
|
||||||
let task = deque.popFirst()
|
|
||||||
task()
|
|
||||||
actor.dataspace.refreshAssertions()
|
|
||||||
return true
|
|
||||||
|
|
||||||
proc runPendingTasks(actor) =
|
|
||||||
while actor.runPendingTask(): discard
|
|
||||||
if actor.pendingActions.len > 0:
|
|
||||||
var pending = move actor.pendingActions
|
|
||||||
actor.dataspace.commitActions(actor, pending)
|
|
||||||
|
|
||||||
proc runPendingTasks(ds: Dataspace) =
|
|
||||||
var runnable = move ds.runnable
|
|
||||||
for actor in runnable:
|
|
||||||
runPendingTasks(actor)
|
|
||||||
|
|
||||||
proc performPendingActions(ds: Dataspace) =
|
|
||||||
var turns = move ds.pendingTurns
|
|
||||||
for turn in turns:
|
|
||||||
for action in turn.actions:
|
|
||||||
action.impl(action, ds, turn.actor)
|
|
||||||
runPendingTasks(ds)
|
|
||||||
|
|
||||||
proc runTasks(ds: Dataspace): bool =
|
|
||||||
ds.runPendingTasks()
|
|
||||||
ds.performPendingActions()
|
|
||||||
result = ds.runnable.len > 0 or ds.pendingTurns.len > 0
|
|
||||||
|
|
||||||
proc stop*(facet; continuation: Script[void] = nil) =
|
|
||||||
facet.parent.map do (parent: Facet):
|
|
||||||
parent.invokeScript do (_: Facet):
|
|
||||||
facet.actor.scheduleTask do ():
|
|
||||||
facet.terminate()
|
|
||||||
if not continuation.isNil:
|
|
||||||
parent.scheduleScript do (parent: Facet):
|
|
||||||
continuation(parent)
|
|
||||||
# ^ TODO: is this the correct scope to use??
|
|
||||||
|
|
||||||
proc addStopHandler*(g: Ground; h: StopHandler) =
|
|
||||||
g.stopHandlers.add(h)
|
|
||||||
|
|
||||||
proc step(g: Ground) {.gcsafe.}
|
|
||||||
|
|
||||||
proc scheduleStep(g: Ground) =
|
|
||||||
if not g.stepScheduled:
|
|
||||||
g.stepScheduled = true
|
|
||||||
asyncdispatch.callSoon: step(g)
|
|
||||||
|
|
||||||
proc beginExternalTask*(facet) =
|
|
||||||
## Inform the ``Ground`` dataspace of a pending external task.
|
|
||||||
## The dataspace will continue to operate until all internal
|
|
||||||
## and external tasks have completed. See ``endExternalTask``.
|
|
||||||
inc facet.actor.dataspace.ground.externalTaskCount
|
|
||||||
|
|
||||||
proc endExternalTask*(facet) =
|
|
||||||
## Inform the ``Ground`` dataspace that an external task has completed.
|
|
||||||
# TODO: automatically do this when the facet stops?
|
|
||||||
let g = facet.actor.dataspace.ground
|
|
||||||
dec g.externalTaskCount
|
|
||||||
scheduleStep g
|
|
||||||
|
|
||||||
proc step(g: Ground) =
|
|
||||||
# TODO: backgroundtasks
|
|
||||||
g.stepScheduled = false
|
|
||||||
if g.dataspace.runTasks():
|
|
||||||
scheduleStep g
|
|
||||||
else:
|
|
||||||
if g.externalTaskCount < 1:
|
|
||||||
for actor in g.dataspace.actors.values:
|
|
||||||
terminate(actor, false)
|
|
||||||
for sh in g.stopHandlers:
|
|
||||||
sh(g.dataspace)
|
|
||||||
reset g.stopHandlers
|
|
||||||
complete(g.future)
|
|
||||||
|
|
||||||
proc bootModule*(name: string; bootProc: ActivationScript): Future[void] =
|
|
||||||
# TODO: better integration with the async dispatcher
|
|
||||||
let g = Ground(future: newFuture[void]"bootModule")
|
|
||||||
g.dataspace = newDataspace(g, name) do (rootFacet: Facet):
|
|
||||||
rootFacet.addStartScript do (rootFacet: Facet):
|
|
||||||
rootFacet.activate(name, bootProc)
|
|
||||||
addTimer(1, true) do (fd: AsyncFD) -> bool:
|
|
||||||
step(g)
|
|
||||||
true
|
|
||||||
return g.future
|
|
||||||
|
|
||||||
template declareField*(facet: Facet; F: untyped; T: typedesc; initial: T): untyped =
|
|
||||||
## Declare getter and setter procs for field `F` of type `T` initalized with `initial`.
|
|
||||||
type DistinctField {.final, unpreservable.} = object of Field
|
|
||||||
discard
|
|
||||||
let `F` {.inject.} = DistinctField(id: facet.actor.dataspace.generateId.FieldId)
|
|
||||||
facet.actor.dataspace.dataflow.defineObservableProperty(`F`.id)
|
|
||||||
facet.fields.add(toPreserve(initial))
|
|
||||||
let fieldOff = facet.fields.high
|
|
||||||
proc set(f: DistinctField; x: T) {.used.} =
|
|
||||||
facet.actor.dataspace.dataflow.recordDamage(f.id)
|
|
||||||
facet.fields[fieldOff] = toPreserve(x)
|
|
||||||
proc set(f: DistinctField; x: Value) {.used.} =
|
|
||||||
facet.actor.dataspace.dataflow.recordDamage(f.id)
|
|
||||||
facet.fields[fieldOff] = x
|
|
||||||
proc get(f: DistinctField): T {.used.} =
|
|
||||||
facet.actor.dataspace.dataflow.recordObservation(f.id)
|
|
||||||
if not fromPreserve(result, facet.fields[fieldOff]):
|
|
||||||
raise newException(ValueError, "cannot convert field " & $F & " to " & $T)
|
|
||||||
proc getPreserve(f: DistinctField): Value {.used.} =
|
|
||||||
facet.actor.dataspace.dataflow.recordObservation(f.id)
|
|
||||||
facet.fields[fieldOff]
|
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
||||||
type EventHandler* = proc (facet: Facet; bindings: seq[Value]) {.gcsafe.}
|
|
||||||
|
|
||||||
proc wrap*(facet: 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
|
|
||||||
|
|
|
@ -4,32 +4,19 @@
|
||||||
import std/[asyncdispatch, monotimes, times]
|
import std/[asyncdispatch, monotimes, times]
|
||||||
import preserves, preserves/records
|
import preserves, preserves/records
|
||||||
import syndicate, syndicate/assertions
|
import syndicate, syndicate/assertions
|
||||||
|
import ../../syndicate/protocols/schemas/timer
|
||||||
type TimeLaterThan* {.record: "TimeLaterThan".} = object
|
|
||||||
`deadline`*: Monotime
|
|
||||||
|
|
||||||
proc prsTimeLaterThan*(deadline: Preserve | Monotime): Preserve =
|
|
||||||
initRecord(symbol("TimeLaterThan"), deadline)
|
|
||||||
|
|
||||||
proc toPreserveHook*(time: Monotime): Preserve =
|
|
||||||
time.ticks.toPreserve
|
|
||||||
|
|
||||||
proc fromPreserveHook*(mt: var Monotime; p: Preserve): bool =
|
|
||||||
if p.kind == pkSignedInteger:
|
|
||||||
mt = cast[MonoTime]((p.int.int64,))
|
|
||||||
result = true
|
|
||||||
|
|
||||||
syndicate timerDriver:
|
syndicate timerDriver:
|
||||||
|
|
||||||
spawn "timer":
|
spawn "timer":
|
||||||
during(observe(prsTimeLaterThan(?deadline))) do (deadline: MonoTime):
|
during(observe(laterThan(?msecs))) do (msecs: float64):
|
||||||
let
|
let
|
||||||
now = getMonoTime()
|
now = getTime().toUnixFloat() * 1_000.0
|
||||||
period = inMilliseconds(deadline - now)
|
period = msecs - now
|
||||||
if period > 0:
|
if period > 0:
|
||||||
getCurrentFacet().beginExternalTask()
|
getCurrentFacet().beginExternalTask()
|
||||||
addTimer(period.int, oneshot = true) do (fd: AsyncFD) -> bool:
|
addTimer(period.int, oneshot = true) do (fd: AsyncFD) -> bool:
|
||||||
react: publish: prsTimeLaterThan(deadline)
|
react: publish: laterThan(deadline)
|
||||||
getCurrentFacet().endExternalTask()
|
getCurrentFacet().endExternalTask()
|
||||||
true
|
true
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -1,7 +1,25 @@
|
||||||
preserves_schema_nim = ../../../preserves/preserves_schema_nim
|
include_rules
|
||||||
|
|
||||||
!preserves_schema_nim = | $(preserves_schema_nim) |> $(preserves_schema_nim) %f |> %B.nim
|
: ../../../preserves/src/preserves/preserves_schema_nim.nim |> !nim |> preserves_schema_nim
|
||||||
|
|
||||||
: foreach ../../../protocols/schemas/*.prs |> !preserves_schema_nim |> {gen}
|
!preserves_schema_nim = | ./preserves_schema_nim |> ./preserves_schema_nim %f |> %B.nim
|
||||||
|
|
||||||
: foreach {gen} | {gen} |> nim check %f; touch %o |> .%B.nim.check {gen}
|
schemas = \
|
||||||
|
dataspace.nim \
|
||||||
|
dataspacePatterns.nim \
|
||||||
|
gatekeeper.nim \
|
||||||
|
protocol.nim \
|
||||||
|
racketEvent.nim \
|
||||||
|
secureChatProtocol.nim \
|
||||||
|
service.nim \
|
||||||
|
simpleChatProtocol.nim \
|
||||||
|
stream.nim \
|
||||||
|
sturdy.nim \
|
||||||
|
tcp.nim \
|
||||||
|
timer.nim \
|
||||||
|
transportAddress.nim \
|
||||||
|
worker.nim \
|
||||||
|
|
||||||
|
: ../../../protocols/schema-bundle.bin |> !preserves_schema_nim |> $(schemas)
|
||||||
|
|
||||||
|
: foreach $(schemas) | $(schemas) |> nim check %f; touch %o |> .%B.nim.check
|
||||||
|
|
|
@ -3,22 +3,12 @@ import
|
||||||
std/typetraits, preserves, dataspacePatterns
|
std/typetraits, preserves, dataspacePatterns
|
||||||
|
|
||||||
type
|
type
|
||||||
Observe*[E = void] {.record: "Observe".} = ref object ## ``<Observe @pattern dataspacePatterns.Pattern @observer #!any>``
|
Observe*[E] {.preservesRecord: "Observe".} = ref object
|
||||||
`pattern`*: dataspacePatterns.Pattern
|
`pattern`*: dataspacePatterns.Pattern[E]
|
||||||
`observer`*: Preserve[E]
|
`observer`*: Preserve[E]
|
||||||
|
|
||||||
proc `observe`*[E = void](`pattern`: dataspacePatterns.Pattern | Preserve[E];
|
|
||||||
`observer`: Preserve[E]): Preserve[E] =
|
|
||||||
## Preserves constructor for ``Observe``.
|
|
||||||
initRecord[E](symbol[E]("Observe"), toPreserve(`pattern`, E),
|
|
||||||
toPreserve(`observer`, E))
|
|
||||||
|
|
||||||
proc toPreserveHook*(`observe`: Observe; E: typedesc): Preserve[E] =
|
|
||||||
initRecord[E](symbol[E]("Observe"), toPreserve(`observe`.`pattern`, E),
|
|
||||||
toPreserve(`observe`.`observer`, E))
|
|
||||||
|
|
||||||
proc `$`*[E](x: Observe[E]): string =
|
proc `$`*[E](x: Observe[E]): string =
|
||||||
`$`(toPreserve(x, E))
|
`$`(toPreserve(x, E))
|
||||||
|
|
||||||
proc `encode`*[E](x: Observe[E]): seq[byte] =
|
proc encode*[E](x: Observe[E]): seq[byte] =
|
||||||
encode(toPreserve(x, E))
|
encode(toPreserve(x, E))
|
||||||
|
|
|
@ -3,164 +3,75 @@ import
|
||||||
std/typetraits, preserves, std/tables, std/tables, std/tables
|
std/typetraits, preserves, std/tables, std/tables, std/tables
|
||||||
|
|
||||||
type
|
type
|
||||||
PatternKind* {.pure.} = enum
|
CRec*[E] {.preservesRecord: "rec".} = ref object
|
||||||
`Ddiscard`, `Dbind`, `Dlit`, `Dcompound`
|
|
||||||
Pattern*[E = void] = ref object ## ``/ DDiscard / DBind / DLit / DCompound``
|
|
||||||
case kind*: PatternKind
|
|
||||||
of PatternKind.`Ddiscard`:
|
|
||||||
`ddiscard`*: DDiscard
|
|
||||||
|
|
||||||
of PatternKind.`Dbind`:
|
|
||||||
`dbind`*: DBind[E]
|
|
||||||
|
|
||||||
of PatternKind.`Dlit`:
|
|
||||||
`dlit`*: DLit[E]
|
|
||||||
|
|
||||||
of PatternKind.`Dcompound`:
|
|
||||||
`dcompound`*: DCompound[E]
|
|
||||||
|
|
||||||
|
|
||||||
DDiscard* {.record: "_".} = object ## ``<_>``
|
|
||||||
discard
|
|
||||||
|
|
||||||
DBind*[E = void] {.record: "bind".} = ref object ## ``<bind @pattern Pattern>``
|
|
||||||
`pattern`*: Pattern[E]
|
|
||||||
|
|
||||||
DLit*[E = void] {.record: "lit".} = ref object ## ``<lit @value any>``
|
|
||||||
`value`*: Preserve[E]
|
|
||||||
|
|
||||||
DcompoundKind* {.pure.} = enum
|
|
||||||
`rec`, `arr`, `dict`
|
|
||||||
DCompoundrec*[E = void] {.record: "compound".} = ref object
|
|
||||||
`ctor`*: CRec[E]
|
|
||||||
`members`*: TableRef[BiggestInt, Pattern[E]]
|
|
||||||
|
|
||||||
DCompoundarr*[E = void] {.record: "compound".} = ref object
|
|
||||||
`ctor`*: CArr
|
|
||||||
`members`*: TableRef[BiggestInt, Pattern[E]]
|
|
||||||
|
|
||||||
DCompounddict*[E = void] {.record: "compound".} = ref object
|
|
||||||
`ctor`*: CDict
|
|
||||||
`members`*: TableRef[Preserve[E], Pattern[E]]
|
|
||||||
|
|
||||||
DCompound*[E = void] = ref object ## ``/ <compound @ctor CRec @members {int : Pattern ...:...}> / <compound @ctor CArr @members {int : Pattern ...:...}> / <compound @ctor CDict @members {any : Pattern ...:...}>``
|
|
||||||
case kind*: DcompoundKind
|
|
||||||
of DcompoundKind.`rec`:
|
|
||||||
`rec`*: DCompoundrec[E]
|
|
||||||
|
|
||||||
of DcompoundKind.`arr`:
|
|
||||||
`arr`*: DCompoundarr[E]
|
|
||||||
|
|
||||||
of DcompoundKind.`dict`:
|
|
||||||
`dict`*: DCompounddict[E]
|
|
||||||
|
|
||||||
|
|
||||||
CRec*[E = void] {.record: "rec".} = ref object ## ``<rec @label any @arity int>``
|
|
||||||
`label`*: Preserve[E]
|
`label`*: Preserve[E]
|
||||||
`arity`*: BiggestInt
|
`arity`*: BiggestInt
|
||||||
|
|
||||||
CArr* {.record: "arr".} = ref object ## ``<arr @arity int>``
|
DLit*[E] {.preservesRecord: "lit".} = ref object
|
||||||
|
`value`*: Preserve[E]
|
||||||
|
|
||||||
|
DBind*[E] {.preservesRecord: "bind".} = ref object
|
||||||
|
`pattern`*: Pattern[E]
|
||||||
|
|
||||||
|
DDiscard* {.preservesRecord: "_".} = object
|
||||||
|
|
||||||
|
CArr* {.preservesRecord: "arr".} = object
|
||||||
`arity`*: BiggestInt
|
`arity`*: BiggestInt
|
||||||
|
|
||||||
CDict* {.record: "dict".} = object ## ``<dict>``
|
DCompoundKind* {.pure.} = enum
|
||||||
discard
|
`rec`, `arr`, `dict`
|
||||||
|
DCompoundRec*[E] {.preservesRecord: "compound".} = ref object
|
||||||
|
`ctor`*: CRec[E]
|
||||||
|
`members`*: Table[BiggestInt, Pattern[E]]
|
||||||
|
|
||||||
proc toPreserveHook*(v: Pattern; E: typedesc): Preserve[E] =
|
DCompoundArr*[E] {.preservesRecord: "compound".} = ref object
|
||||||
case v.kind
|
`ctor`*: CArr
|
||||||
of PatternKind.`Ddiscard`:
|
`members`*: Table[BiggestInt, Pattern[E]]
|
||||||
toPreserve(v.`ddiscard`, E)
|
|
||||||
of PatternKind.`Dbind`:
|
|
||||||
toPreserve(v.`dbind`, E)
|
|
||||||
of PatternKind.`Dlit`:
|
|
||||||
toPreserve(v.`dlit`, E)
|
|
||||||
of PatternKind.`Dcompound`:
|
|
||||||
toPreserve(v.`dcompound`, E)
|
|
||||||
|
|
||||||
proc fromPreserveHook*[E](v: var Pattern; pr: Preserve[E]): bool =
|
DCompoundDict*[E] {.preservesRecord: "compound".} = ref object
|
||||||
if isRecord(pr) and pr.label.isSymbol("DDiscard"):
|
`ctor`*: CDict
|
||||||
v = Pattern(kind: PatternKind.`Ddiscard`)
|
`members`*: Table[Preserve[E], Pattern[E]]
|
||||||
result = fromPreserve(v.`ddiscard`, pr)
|
|
||||||
elif isRecord(pr) and pr.label.isSymbol("DBind"):
|
|
||||||
v = Pattern(kind: PatternKind.`Dbind`)
|
|
||||||
result = fromPreserve(v.`dbind`, pr)
|
|
||||||
elif isRecord(pr) and pr.label.isSymbol("DLit"):
|
|
||||||
v = Pattern(kind: PatternKind.`Dlit`)
|
|
||||||
result = fromPreserve(v.`dlit`, pr)
|
|
||||||
elif false: ## snkOr - / <compound @ctor CRec @members {int : Pattern ...:...}> / <compound @ctor CArr @members {int : Pattern ...:...}> / <compound @ctor CDict @members {any : Pattern ...:...}>
|
|
||||||
discard
|
|
||||||
|
|
||||||
proc `dDiscard`*[E = void](): Preserve[E] =
|
`DCompound`*[E] {.preservesOr.} = ref object
|
||||||
## Preserves constructor for ``DDiscard``.
|
case orKind*: DCompoundKind
|
||||||
initRecord[E](symbol[E]("_"))
|
|
||||||
|
|
||||||
proc toPreserveHook*(`ddiscard`: DDiscard; E: typedesc): Preserve[E] =
|
|
||||||
initRecord[E](symbol[E]("_"))
|
|
||||||
|
|
||||||
proc `dBind`*[E = void](`pattern`: Pattern | Preserve[E]): Preserve[E] =
|
|
||||||
## Preserves constructor for ``DBind``.
|
|
||||||
initRecord[E](symbol[E]("bind"), toPreserve(`pattern`, E))
|
|
||||||
|
|
||||||
proc toPreserveHook*(`dbind`: DBind; E: typedesc): Preserve[E] =
|
|
||||||
initRecord[E](symbol[E]("bind"), toPreserve(`dbind`.`pattern`, E))
|
|
||||||
|
|
||||||
proc `dLit`*[E = void](`value`: Preserve[E]): Preserve[E] =
|
|
||||||
## Preserves constructor for ``DLit``.
|
|
||||||
initRecord[E](symbol[E]("lit"), toPreserve(`value`, E))
|
|
||||||
|
|
||||||
proc toPreserveHook*(`dlit`: DLit; E: typedesc): Preserve[E] =
|
|
||||||
initRecord[E](symbol[E]("lit"), toPreserve(`dlit`.`value`, E))
|
|
||||||
|
|
||||||
proc toPreserveHook*(v: DCompound; E: typedesc): Preserve[E] =
|
|
||||||
case v.kind
|
|
||||||
of DCompoundKind.`rec`:
|
of DCompoundKind.`rec`:
|
||||||
toPreserve(v.`rec`, E)
|
`rec`*: DCompoundRec[E]
|
||||||
|
|
||||||
of DCompoundKind.`arr`:
|
of DCompoundKind.`arr`:
|
||||||
toPreserve(v.`arr`, E)
|
`arr`*: DCompoundArr[E]
|
||||||
|
|
||||||
of DCompoundKind.`dict`:
|
of DCompoundKind.`dict`:
|
||||||
toPreserve(v.`dict`, E)
|
`dict`*: DCompoundDict[E]
|
||||||
|
|
||||||
proc fromPreserveHook*[E](v: var DCompound; pr: Preserve[E]): bool =
|
|
||||||
if isRecord(pr) and pr.label.isSymbol("rec"):
|
|
||||||
v = DCompound(kind: DCompoundKind.`rec`)
|
|
||||||
result = fromPreserve(v.`rec`, pr)
|
|
||||||
elif isRecord(pr) and pr.label.isSymbol("arr"):
|
|
||||||
v = DCompound(kind: DCompoundKind.`arr`)
|
|
||||||
result = fromPreserve(v.`arr`, pr)
|
|
||||||
elif isRecord(pr) and pr.label.isSymbol("dict"):
|
|
||||||
v = DCompound(kind: DCompoundKind.`dict`)
|
|
||||||
result = fromPreserve(v.`dict`, pr)
|
|
||||||
|
|
||||||
proc `cRec`*[E = void](`label`: Preserve[E]; `arity`: BiggestInt | Preserve[E]): Preserve[
|
CDict* {.preservesRecord: "dict".} = object
|
||||||
E] =
|
|
||||||
## Preserves constructor for ``CRec``.
|
|
||||||
initRecord[E](symbol[E]("rec"), toPreserve(`label`, E), toPreserve(`arity`, E))
|
|
||||||
|
|
||||||
proc toPreserveHook*(`crec`: CRec; E: typedesc): Preserve[E] =
|
PatternKind* {.pure.} = enum
|
||||||
initRecord[E](symbol[E]("rec"), toPreserve(`crec`.`label`, E),
|
`DDiscard`, `DBind`, `DLit`, `DCompound`
|
||||||
toPreserve(`crec`.`arity`, E))
|
`Pattern`*[E] {.preservesOr.} = ref object
|
||||||
|
case orKind*: PatternKind
|
||||||
|
of PatternKind.`DDiscard`:
|
||||||
|
`ddiscard`*: DDiscard
|
||||||
|
|
||||||
proc `cArr`*[E = void](`arity`: BiggestInt | Preserve[E]): Preserve[E] =
|
of PatternKind.`DBind`:
|
||||||
## Preserves constructor for ``CArr``.
|
`dbind`*: DBind[E]
|
||||||
initRecord[E](symbol[E]("arr"), toPreserve(`arity`, E))
|
|
||||||
|
|
||||||
proc toPreserveHook*(`carr`: CArr; E: typedesc): Preserve[E] =
|
of PatternKind.`DLit`:
|
||||||
initRecord[E](symbol[E]("arr"), toPreserve(`carr`.`arity`, E))
|
`dlit`*: DLit[E]
|
||||||
|
|
||||||
proc `cDict`*[E = void](): Preserve[E] =
|
of PatternKind.`DCompound`:
|
||||||
## Preserves constructor for ``CDict``.
|
`dcompound`*: DCompound[E]
|
||||||
initRecord[E](symbol[E]("dict"))
|
|
||||||
|
|
||||||
proc toPreserveHook*(`cdict`: CDict; E: typedesc): Preserve[E] =
|
|
||||||
initRecord[E](symbol[E]("dict"))
|
|
||||||
|
|
||||||
proc `$`*[E](x: Pattern[E] | DDiscard | DBind[E] | DLit[E] | DCompound[E] |
|
proc `$`*[E](x: CRec[E] | DLit[E] | DBind[E] | DCompound[E] | Pattern[E]): string =
|
||||||
CRec[E] |
|
|
||||||
CArr |
|
|
||||||
CDict): string =
|
|
||||||
`$`(toPreserve(x, E))
|
`$`(toPreserve(x, E))
|
||||||
|
|
||||||
proc `encode`*[E](x: Pattern[E] | DDiscard | DBind[E] | DLit[E] | DCompound[E] |
|
proc encode*[E](x: CRec[E] | DLit[E] | DBind[E] | DCompound[E] | Pattern[E]): seq[
|
||||||
CRec[E] |
|
byte] =
|
||||||
CArr |
|
|
||||||
CDict): seq[byte] =
|
|
||||||
encode(toPreserve(x, E))
|
encode(toPreserve(x, E))
|
||||||
|
|
||||||
|
proc `$`*(x: DDiscard | CArr | CDict): string =
|
||||||
|
`$`(toPreserve(x))
|
||||||
|
|
||||||
|
proc encode*(x: DDiscard | CArr | CDict): seq[byte] =
|
||||||
|
encode(toPreserve(x))
|
||||||
|
|
|
@ -3,37 +3,17 @@ import
|
||||||
std/typetraits, preserves, sturdy
|
std/typetraits, preserves, sturdy
|
||||||
|
|
||||||
type
|
type
|
||||||
Resolve*[E = void] {.record: "resolve".} = ref object ## ``<resolve @sturdyref sturdy.SturdyRef @observer #!#!any>``
|
Bind*[E] {.preservesRecord: "bind".} = ref object
|
||||||
`sturdyref`*: sturdy.SturdyRef
|
|
||||||
`observer`*: Preserve[E]
|
|
||||||
|
|
||||||
Bind*[E = void] {.record: "bind".} = ref object ## ``<bind @oid any @key bytes @target #!any>``
|
|
||||||
`oid`*: Preserve[E]
|
`oid`*: Preserve[E]
|
||||||
`key`*: seq[byte]
|
`key`*: seq[byte]
|
||||||
`target`*: Preserve[E]
|
`target`*: Preserve[E]
|
||||||
|
|
||||||
proc `resolve`*[E = void](`sturdyref`: sturdy.SturdyRef | Preserve[E];
|
Resolve*[E] {.preservesRecord: "resolve".} = ref object
|
||||||
`observer`: Preserve[E]): Preserve[E] =
|
`sturdyref`*: sturdy.SturdyRef[E]
|
||||||
## Preserves constructor for ``Resolve``.
|
`observer`*: Preserve[E]
|
||||||
initRecord[E](symbol[E]("resolve"), toPreserve(`sturdyref`, E),
|
|
||||||
toPreserve(`observer`, E))
|
|
||||||
|
|
||||||
proc toPreserveHook*(`resolve`: Resolve; E: typedesc): Preserve[E] =
|
proc `$`*[E](x: Bind[E] | Resolve[E]): string =
|
||||||
initRecord[E](symbol[E]("resolve"), toPreserve(`resolve`.`sturdyref`, E),
|
|
||||||
toPreserve(`resolve`.`observer`, E))
|
|
||||||
|
|
||||||
proc `bind`*[E = void](`oid`: Preserve[E]; `key`: seq[byte] | Preserve[E];
|
|
||||||
`target`: Preserve[E]): Preserve[E] =
|
|
||||||
## Preserves constructor for ``Bind``.
|
|
||||||
initRecord[E](symbol[E]("bind"), toPreserve(`oid`, E), toPreserve(`key`, E),
|
|
||||||
toPreserve(`target`, E))
|
|
||||||
|
|
||||||
proc toPreserveHook*(`bind`: Bind; E: typedesc): Preserve[E] =
|
|
||||||
initRecord[E](symbol[E]("bind"), toPreserve(`bind`.`oid`, E),
|
|
||||||
toPreserve(`bind`.`key`, E), toPreserve(`bind`.`target`, E))
|
|
||||||
|
|
||||||
proc `$`*[E](x: Resolve[E] | Bind[E]): string =
|
|
||||||
`$`(toPreserve(x, E))
|
`$`(toPreserve(x, E))
|
||||||
|
|
||||||
proc `encode`*[E](x: Resolve[E] | Bind[E]): seq[byte] =
|
proc encode*[E](x: Bind[E] | Resolve[E]): seq[byte] =
|
||||||
encode(toPreserve(x, E))
|
encode(toPreserve(x, E))
|
||||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -3,10 +3,35 @@ import
|
||||||
std/typetraits, preserves
|
std/typetraits, preserves
|
||||||
|
|
||||||
type
|
type
|
||||||
|
Error*[E] {.preservesRecord: "error".} = ref object
|
||||||
|
`message`*: string
|
||||||
|
`detail`*: Preserve[E]
|
||||||
|
|
||||||
|
Turn*[E] = seq[TurnEvent[E]]
|
||||||
|
Message*[E] {.preservesRecord: "message".} = ref object
|
||||||
|
`body`*: Assertion[E]
|
||||||
|
|
||||||
|
Retract* {.preservesRecord: "retract".} = object
|
||||||
|
`handle`*: Handle
|
||||||
|
|
||||||
|
Assert*[E] {.preservesRecord: "assert".} = ref object
|
||||||
|
`assertion`*: Assertion[E]
|
||||||
|
`handle`*: Handle
|
||||||
|
|
||||||
|
Sync*[E] {.preservesRecord: "sync".} = ref object
|
||||||
|
`peer`*: Preserve[E]
|
||||||
|
|
||||||
|
TurnEvent*[E] {.preservesTuple.} = ref object
|
||||||
|
`oid`*: Oid
|
||||||
|
`event`*: Event[E]
|
||||||
|
|
||||||
|
Oid* = BiggestInt
|
||||||
|
Assertion*[E] = Preserve[E]
|
||||||
|
Handle* = BiggestInt
|
||||||
PacketKind* {.pure.} = enum
|
PacketKind* {.pure.} = enum
|
||||||
`Turn`, `Error`
|
`Turn`, `Error`
|
||||||
Packet*[E = void] = ref object ## ``/ Turn / Error``
|
`Packet`*[E] {.preservesOr.} = ref object
|
||||||
case kind*: PacketKind
|
case orKind*: PacketKind
|
||||||
of PacketKind.`Turn`:
|
of PacketKind.`Turn`:
|
||||||
`turn`*: Turn[E]
|
`turn`*: Turn[E]
|
||||||
|
|
||||||
|
@ -14,16 +39,10 @@ type
|
||||||
`error`*: Error[E]
|
`error`*: Error[E]
|
||||||
|
|
||||||
|
|
||||||
Error*[E = void] {.record: "error".} = ref object ## ``<error @message string @detail any>``
|
|
||||||
`message`*: string
|
|
||||||
`detail`*: Preserve[E]
|
|
||||||
|
|
||||||
Assertion*[E = void] = Preserve[E] ## ``any``
|
|
||||||
Handle* = distinct BiggestInt ## ``int``
|
|
||||||
EventKind* {.pure.} = enum
|
EventKind* {.pure.} = enum
|
||||||
`Assert`, `Retract`, `Message`, `Sync`
|
`Assert`, `Retract`, `Message`, `Sync`
|
||||||
Event*[E = void] = ref object ## ``/ Assert / Retract / Message / Sync``
|
`Event`*[E] {.preservesOr.} = ref object
|
||||||
case kind*: EventKind
|
case orKind*: EventKind
|
||||||
of EventKind.`Assert`:
|
of EventKind.`Assert`:
|
||||||
`assert`*: Assert[E]
|
`assert`*: Assert[E]
|
||||||
|
|
||||||
|
@ -34,124 +53,23 @@ type
|
||||||
`message`*: Message[E]
|
`message`*: Message[E]
|
||||||
|
|
||||||
of EventKind.`Sync`:
|
of EventKind.`Sync`:
|
||||||
`sync`*: Sync
|
`sync`*: Sync[E]
|
||||||
|
|
||||||
|
|
||||||
Oid* = distinct BiggestInt ## ``int``
|
proc `$`*[E](x: Error[E] | Turn[E] | Message[E] | Assert[E] | Sync[E] |
|
||||||
Turn*[E = void] = seq[TurnEvent[E]] ## ``[ TurnEvent ... ]``
|
|
||||||
TurnEvent*[E = void] = tuple[`oid`: Oid, `event`: Event[E]] ## ``[@oid Oid @event Event]``
|
|
||||||
Assert*[E = void] {.record: "assert".} = ref object ## ``<assert @assertion Assertion @handle Handle>``
|
|
||||||
`assertion`*: Assertion[E]
|
|
||||||
`handle`*: Handle
|
|
||||||
|
|
||||||
Retract* {.record: "retract".} = ref object ## ``<retract @handle Handle>``
|
|
||||||
`handle`*: Handle
|
|
||||||
|
|
||||||
Message*[E = void] {.record: "message".} = ref object ## ``<message @body Assertion>``
|
|
||||||
`body`*: Assertion[E]
|
|
||||||
|
|
||||||
Sync* {.record: "sync".} = ref object ## ``<sync @peer #!#t>``
|
|
||||||
`peer`*: bool
|
|
||||||
|
|
||||||
proc toPreserveHook*(v: Packet; E: typedesc): Preserve[E] =
|
|
||||||
case v.kind
|
|
||||||
of PacketKind.`Turn`:
|
|
||||||
toPreserve(v.`turn`, E)
|
|
||||||
of PacketKind.`Error`:
|
|
||||||
toPreserve(v.`error`, E)
|
|
||||||
|
|
||||||
proc fromPreserveHook*[E](v: var Packet; pr: Preserve[E]): bool =
|
|
||||||
if false:
|
|
||||||
discard
|
|
||||||
elif isRecord(pr) and pr.label.isSymbol("Error"):
|
|
||||||
v = Packet(kind: PacketKind.`Error`)
|
|
||||||
result = fromPreserve(v.`error`, pr)
|
|
||||||
|
|
||||||
proc `error`*[E = void](`message`: string | Preserve[E]; `detail`: Preserve[E]): Preserve[
|
|
||||||
E] =
|
|
||||||
## Preserves constructor for ``Error``.
|
|
||||||
initRecord[E](symbol[E]("error"), toPreserve(`message`, E),
|
|
||||||
toPreserve(`detail`, E))
|
|
||||||
|
|
||||||
proc toPreserveHook*(`error`: Error; E: typedesc): Preserve[E] =
|
|
||||||
initRecord[E](symbol[E]("error"), toPreserve(`error`.`message`, E),
|
|
||||||
toPreserve(`error`.`detail`, E))
|
|
||||||
|
|
||||||
proc toPreserveHook*(v: Event; E: typedesc): Preserve[E] =
|
|
||||||
case v.kind
|
|
||||||
of EventKind.`Assert`:
|
|
||||||
toPreserve(v.`assert`, E)
|
|
||||||
of EventKind.`Retract`:
|
|
||||||
toPreserve(v.`retract`, E)
|
|
||||||
of EventKind.`Message`:
|
|
||||||
toPreserve(v.`message`, E)
|
|
||||||
of EventKind.`Sync`:
|
|
||||||
toPreserve(v.`sync`, E)
|
|
||||||
|
|
||||||
proc fromPreserveHook*[E](v: var Event; pr: Preserve[E]): bool =
|
|
||||||
if isRecord(pr) and pr.label.isSymbol("Assert"):
|
|
||||||
v = Event(kind: EventKind.`Assert`)
|
|
||||||
result = fromPreserve(v.`assert`, pr)
|
|
||||||
elif isRecord(pr) and pr.label.isSymbol("Retract"):
|
|
||||||
v = Event(kind: EventKind.`Retract`)
|
|
||||||
result = fromPreserve(v.`retract`, pr)
|
|
||||||
elif isRecord(pr) and pr.label.isSymbol("Message"):
|
|
||||||
v = Event(kind: EventKind.`Message`)
|
|
||||||
result = fromPreserve(v.`message`, pr)
|
|
||||||
elif isRecord(pr) and pr.label.isSymbol("Sync"):
|
|
||||||
v = Event(kind: EventKind.`Sync`)
|
|
||||||
result = fromPreserve(v.`sync`, pr)
|
|
||||||
|
|
||||||
proc toPreserveHook*(`turnevent`: TurnEvent; E: typedesc): Preserve[E] =
|
|
||||||
Preserve[E](kind: pkSequence, sequence: @[toPreserve(`turnevent`.`oid`, E),
|
|
||||||
toPreserve(`turnevent`.`event`, E)])
|
|
||||||
|
|
||||||
proc `assert`*[E = void](`assertion`: Assertion | Preserve[E];
|
|
||||||
`handle`: Handle | Preserve[E]): Preserve[E] =
|
|
||||||
## Preserves constructor for ``Assert``.
|
|
||||||
initRecord[E](symbol[E]("assert"), toPreserve(`assertion`, E),
|
|
||||||
toPreserve(`handle`, E))
|
|
||||||
|
|
||||||
proc toPreserveHook*(`assert`: Assert; E: typedesc): Preserve[E] =
|
|
||||||
initRecord[E](symbol[E]("assert"), toPreserve(`assert`.`assertion`, E),
|
|
||||||
toPreserve(`assert`.`handle`, E))
|
|
||||||
|
|
||||||
proc `retract`*[E = void](`handle`: Handle | Preserve[E]): Preserve[E] =
|
|
||||||
## Preserves constructor for ``Retract``.
|
|
||||||
initRecord[E](symbol[E]("retract"), toPreserve(`handle`, E))
|
|
||||||
|
|
||||||
proc toPreserveHook*(`retract`: Retract; E: typedesc): Preserve[E] =
|
|
||||||
initRecord[E](symbol[E]("retract"), toPreserve(`retract`.`handle`, E))
|
|
||||||
|
|
||||||
proc `message`*[E = void](`body`: Assertion | Preserve[E]): Preserve[E] =
|
|
||||||
## Preserves constructor for ``Message``.
|
|
||||||
initRecord[E](symbol[E]("message"), toPreserve(`body`, E))
|
|
||||||
|
|
||||||
proc toPreserveHook*(`message`: Message; E: typedesc): Preserve[E] =
|
|
||||||
initRecord[E](symbol[E]("message"), toPreserve(`message`.`body`, E))
|
|
||||||
|
|
||||||
proc `sync`*[E = void](`peer`: Preserve[E]): Preserve[E] =
|
|
||||||
## Preserves constructor for ``Sync``.
|
|
||||||
initRecord[E](symbol[E]("sync"), toPreserve(`peer`, E))
|
|
||||||
|
|
||||||
proc toPreserveHook*(`sync`: Sync; E: typedesc): Preserve[E] =
|
|
||||||
initRecord[E](symbol[E]("sync"), toPreserve(`sync`.`peer`, E))
|
|
||||||
|
|
||||||
proc `$`*[E](x: Packet[E] | Error[E] | Assertion[E] | Handle | Event[E] | Oid |
|
|
||||||
Turn[E] |
|
|
||||||
TurnEvent[E] |
|
TurnEvent[E] |
|
||||||
Assert[E] |
|
Packet[E] |
|
||||||
Retract |
|
Event[E]): string =
|
||||||
Message[E] |
|
|
||||||
Sync): string =
|
|
||||||
`$`(toPreserve(x, E))
|
`$`(toPreserve(x, E))
|
||||||
|
|
||||||
proc `encode`*[E](x: Packet[E] | Error[E] | Assertion[E] | Handle | Event[E] |
|
proc encode*[E](x: Error[E] | Turn[E] | Message[E] | Assert[E] | Sync[E] |
|
||||||
Oid |
|
|
||||||
Turn[E] |
|
|
||||||
TurnEvent[E] |
|
TurnEvent[E] |
|
||||||
Assert[E] |
|
Packet[E] |
|
||||||
Retract |
|
Event[E]): seq[byte] =
|
||||||
Message[E] |
|
|
||||||
Sync): seq[byte] =
|
|
||||||
encode(toPreserve(x, E))
|
encode(toPreserve(x, E))
|
||||||
|
|
||||||
|
proc `$`*(x: Retract | Oid | Handle): string =
|
||||||
|
`$`(toPreserve(x))
|
||||||
|
|
||||||
|
proc encode*(x: Retract | Oid | Handle): seq[byte] =
|
||||||
|
encode(toPreserve(x))
|
||||||
|
|
|
@ -3,23 +3,12 @@ import
|
||||||
std/typetraits, preserves
|
std/typetraits, preserves
|
||||||
|
|
||||||
type
|
type
|
||||||
RacketEvent*[E = void] {.record: "racket-event".} = ref object ## ``<racket-event @source #!any @event #!any>``
|
RacketEvent*[E] {.preservesRecord: "racket-event".} = ref object
|
||||||
`source`*: Preserve[E]
|
`source`*: Preserve[E]
|
||||||
`event`*: Preserve[E]
|
`event`*: Preserve[E]
|
||||||
|
|
||||||
proc `racketEvent`*[E = void](`source`: Preserve[E]; `event`: Preserve[E]): Preserve[
|
|
||||||
E] =
|
|
||||||
## Preserves constructor for ``RacketEvent``.
|
|
||||||
initRecord[E](symbol[E]("racket-event"), toPreserve(`source`, E),
|
|
||||||
toPreserve(`event`, E))
|
|
||||||
|
|
||||||
proc toPreserveHook*(`racketevent`: RacketEvent; E: typedesc): Preserve[E] =
|
|
||||||
initRecord[E](symbol[E]("racket-event"),
|
|
||||||
toPreserve(`racketevent`.`source`, E),
|
|
||||||
toPreserve(`racketevent`.`event`, E))
|
|
||||||
|
|
||||||
proc `$`*[E](x: RacketEvent[E]): string =
|
proc `$`*[E](x: RacketEvent[E]): string =
|
||||||
`$`(toPreserve(x, E))
|
`$`(toPreserve(x, E))
|
||||||
|
|
||||||
proc `encode`*[E](x: RacketEvent[E]): seq[byte] =
|
proc encode*[E](x: RacketEvent[E]): seq[byte] =
|
||||||
encode(toPreserve(x, E))
|
encode(toPreserve(x, E))
|
||||||
|
|
|
@ -3,159 +3,71 @@ import
|
||||||
std/typetraits, preserves
|
std/typetraits, preserves
|
||||||
|
|
||||||
type
|
type
|
||||||
UserId* = distinct BiggestInt ## ``int``
|
UserId* = BiggestInt
|
||||||
Join* {.record: "joinedUser".} = ref object ## ``<joinedUser @uid UserId @handle #!Session>``
|
NickConflict* {.preservesRecord: "nickConflict".} = object
|
||||||
|
|
||||||
|
NickClaimResponseKind* {.pure.} = enum
|
||||||
|
`true`, `NickConflict`
|
||||||
|
`NickClaimResponse`* {.preservesOr.} = object
|
||||||
|
case orKind*: NickClaimResponseKind
|
||||||
|
of NickClaimResponseKind.`true`:
|
||||||
|
`true`* {.preservesLiteral: "#t".}: bool
|
||||||
|
|
||||||
|
of NickClaimResponseKind.`NickConflict`:
|
||||||
|
`nickconflict`*: NickConflict
|
||||||
|
|
||||||
|
|
||||||
|
Join*[E] {.preservesRecord: "joinedUser".} = ref object
|
||||||
`uid`*: UserId
|
`uid`*: UserId
|
||||||
`handle`*: Session
|
`handle`*: Preserve[E]
|
||||||
|
|
||||||
SessionKind* {.pure.} = enum
|
SessionKind* {.pure.} = enum
|
||||||
`observeusers`, `observespeech`, `Nickclaim`, `Says`
|
`observeUsers`, `observeSpeech`, `NickClaim`, `Says`
|
||||||
Sessionobserveusers* {.record: "Observe".} = ref object
|
SessionObserveUsers*[E] {.preservesRecord: "Observe".} = ref object
|
||||||
`user`*: string
|
`data`* {.preservesLiteral: "user".}: bool
|
||||||
`observer`*: UserInfo
|
`observer`*: Preserve[E]
|
||||||
|
|
||||||
Sessionobservespeech* {.record: "Observe".} = ref object
|
SessionObserveSpeech*[E] {.preservesRecord: "Observe".} = ref object
|
||||||
`says`*: string
|
`data`* {.preservesLiteral: "says".}: bool
|
||||||
`observer`*: Says
|
`observer`*: Preserve[E]
|
||||||
|
|
||||||
Session* = ref object ## ``/ <Observe <<lit>user> @observer #!UserInfo> / <Observe <<lit>says> @observer #!Says> / NickClaim / Says``
|
`Session`*[E] {.preservesOr.} = ref object
|
||||||
case kind*: SessionKind
|
case orKind*: SessionKind
|
||||||
of SessionKind.`observeusers`:
|
of SessionKind.`observeUsers`:
|
||||||
`observeusers`*: Sessionobserveusers
|
`observeusers`*: SessionObserveUsers[E]
|
||||||
|
|
||||||
of SessionKind.`observespeech`:
|
of SessionKind.`observeSpeech`:
|
||||||
`observespeech`*: Sessionobservespeech
|
`observespeech`*: SessionObserveSpeech[E]
|
||||||
|
|
||||||
of SessionKind.`Nickclaim`:
|
of SessionKind.`NickClaim`:
|
||||||
`nickclaim`*: NickClaim
|
`nickclaim`*: NickClaim[E]
|
||||||
|
|
||||||
of SessionKind.`Says`:
|
of SessionKind.`Says`:
|
||||||
`says`*: Says
|
`says`*: Says
|
||||||
|
|
||||||
|
|
||||||
NickClaim* {.record: "claimNick".} = ref object ## ``<claimNick @uid UserId @name string @k #!NickClaimResponse>``
|
UserInfo* {.preservesRecord: "user".} = object
|
||||||
`uid`*: UserId
|
|
||||||
`name`*: string
|
|
||||||
`k`*: NickClaimResponse
|
|
||||||
|
|
||||||
NickclaimresponseKind* {.pure.} = enum
|
|
||||||
`true`, `Nickconflict`
|
|
||||||
NickClaimResponsetrue* = bool
|
|
||||||
NickClaimResponse* = ref object ## ``/ =#t / NickConflict``
|
|
||||||
case kind*: NickclaimresponseKind
|
|
||||||
of NickclaimresponseKind.`true`:
|
|
||||||
discard
|
|
||||||
|
|
||||||
of NickclaimresponseKind.`Nickconflict`:
|
|
||||||
`nickconflict`*: NickConflict
|
|
||||||
|
|
||||||
|
|
||||||
UserInfo* {.record: "user".} = ref object ## ``<user @uid UserId @name string>``
|
|
||||||
`uid`*: UserId
|
`uid`*: UserId
|
||||||
`name`*: string
|
`name`*: string
|
||||||
|
|
||||||
Says* {.record: "says".} = ref object ## ``<says @who UserId @what string>``
|
NickClaim*[E] {.preservesRecord: "claimNick".} = ref object
|
||||||
|
`uid`*: UserId
|
||||||
|
`name`*: string
|
||||||
|
`k`*: Preserve[E]
|
||||||
|
|
||||||
|
Says* {.preservesRecord: "says".} = object
|
||||||
`who`*: UserId
|
`who`*: UserId
|
||||||
`what`*: string
|
`what`*: string
|
||||||
|
|
||||||
NickConflict* {.record: "nickConflict".} = object ## ``<nickConflict>``
|
proc `$`*[E](x: Join[E] | Session[E] | NickClaim[E]): string =
|
||||||
discard
|
|
||||||
|
|
||||||
proc `join`*[E = void](`uid`: UserId | Preserve[E]; `handle`: Preserve[E]): Preserve[
|
|
||||||
E] =
|
|
||||||
## Preserves constructor for ``Join``.
|
|
||||||
initRecord[E](symbol[E]("joinedUser"), toPreserve(`uid`, E),
|
|
||||||
toPreserve(`handle`, E))
|
|
||||||
|
|
||||||
proc toPreserveHook*(`join`: Join; E: typedesc): Preserve[E] =
|
|
||||||
initRecord[E](symbol[E]("joinedUser"), toPreserve(`join`.`uid`, E),
|
|
||||||
toPreserve(`join`.`handle`, E))
|
|
||||||
|
|
||||||
proc toPreserveHook*(v: Session; E: typedesc): Preserve[E] =
|
|
||||||
case v.kind
|
|
||||||
of SessionKind.`observeusers`:
|
|
||||||
toPreserve(v.`observeusers`, E)
|
|
||||||
of SessionKind.`observespeech`:
|
|
||||||
toPreserve(v.`observespeech`, E)
|
|
||||||
of SessionKind.`Nickclaim`:
|
|
||||||
toPreserve(v.`nickclaim`, E)
|
|
||||||
of SessionKind.`Says`:
|
|
||||||
toPreserve(v.`says`, E)
|
|
||||||
|
|
||||||
proc fromPreserveHook*[E](v: var Session; pr: Preserve[E]): bool =
|
|
||||||
if isRecord(pr) and pr.label.isSymbol("observeUsers"):
|
|
||||||
v = Session(kind: SessionKind.`observeusers`)
|
|
||||||
result = fromPreserve(v.`observeusers`, pr)
|
|
||||||
elif isRecord(pr) and pr.label.isSymbol("observeSpeech"):
|
|
||||||
v = Session(kind: SessionKind.`observespeech`)
|
|
||||||
result = fromPreserve(v.`observespeech`, pr)
|
|
||||||
elif isRecord(pr) and pr.label.isSymbol("NickClaim"):
|
|
||||||
v = Session(kind: SessionKind.`Nickclaim`)
|
|
||||||
result = fromPreserve(v.`nickclaim`, pr)
|
|
||||||
elif isRecord(pr) and pr.label.isSymbol("Says"):
|
|
||||||
v = Session(kind: SessionKind.`Says`)
|
|
||||||
result = fromPreserve(v.`says`, pr)
|
|
||||||
|
|
||||||
proc `nickClaim`*[E = void](`uid`: UserId | Preserve[E];
|
|
||||||
`name`: string | Preserve[E]; `k`: Preserve[E]): Preserve[
|
|
||||||
E] =
|
|
||||||
## Preserves constructor for ``NickClaim``.
|
|
||||||
initRecord[E](symbol[E]("claimNick"), toPreserve(`uid`, E),
|
|
||||||
toPreserve(`name`, E), toPreserve(`k`, E))
|
|
||||||
|
|
||||||
proc toPreserveHook*(`nickclaim`: NickClaim; E: typedesc): Preserve[E] =
|
|
||||||
initRecord[E](symbol[E]("claimNick"), toPreserve(`nickclaim`.`uid`, E),
|
|
||||||
toPreserve(`nickclaim`.`name`, E),
|
|
||||||
toPreserve(`nickclaim`.`k`, E))
|
|
||||||
|
|
||||||
proc toPreserveHook*(v: NickClaimResponse; E: typedesc): Preserve[E] =
|
|
||||||
case v.kind
|
|
||||||
of NickClaimResponseKind.`true`:
|
|
||||||
Preserve[E](kind: pkBoolean, bool: true)
|
|
||||||
of NickClaimResponseKind.`Nickconflict`:
|
|
||||||
toPreserve(v.`nickconflict`, E)
|
|
||||||
|
|
||||||
proc fromPreserveHook*[E](v: var NickClaimResponse; pr: Preserve[E]): bool =
|
|
||||||
if pr.kind == pkBoolean and pr.bool == true:
|
|
||||||
v = NickClaimResponse(kind: NickClaimResponseKind.`true`)
|
|
||||||
result = true
|
|
||||||
elif isRecord(pr) and pr.label.isSymbol("NickConflict"):
|
|
||||||
v = NickClaimResponse(kind: NickClaimResponseKind.`Nickconflict`)
|
|
||||||
result = fromPreserve(v.`nickconflict`, pr)
|
|
||||||
|
|
||||||
proc `userInfo`*[E = void](`uid`: UserId | Preserve[E];
|
|
||||||
`name`: string | Preserve[E]): Preserve[E] =
|
|
||||||
## Preserves constructor for ``UserInfo``.
|
|
||||||
initRecord[E](symbol[E]("user"), toPreserve(`uid`, E), toPreserve(`name`, E))
|
|
||||||
|
|
||||||
proc toPreserveHook*(`userinfo`: UserInfo; E: typedesc): Preserve[E] =
|
|
||||||
initRecord[E](symbol[E]("user"), toPreserve(`userinfo`.`uid`, E),
|
|
||||||
toPreserve(`userinfo`.`name`, E))
|
|
||||||
|
|
||||||
proc `says`*[E = void](`who`: UserId | Preserve[E]; `what`: string | Preserve[E]): Preserve[
|
|
||||||
E] =
|
|
||||||
## Preserves constructor for ``Says``.
|
|
||||||
initRecord[E](symbol[E]("says"), toPreserve(`who`, E), toPreserve(`what`, E))
|
|
||||||
|
|
||||||
proc toPreserveHook*(`says`: Says; E: typedesc): Preserve[E] =
|
|
||||||
initRecord[E](symbol[E]("says"), toPreserve(`says`.`who`, E),
|
|
||||||
toPreserve(`says`.`what`, E))
|
|
||||||
|
|
||||||
proc `nickConflict`*[E = void](): Preserve[E] =
|
|
||||||
## Preserves constructor for ``NickConflict``.
|
|
||||||
initRecord[E](symbol[E]("nickConflict"))
|
|
||||||
|
|
||||||
proc toPreserveHook*(`nickconflict`: NickConflict; E: typedesc): Preserve[E] =
|
|
||||||
initRecord[E](symbol[E]("nickConflict"))
|
|
||||||
|
|
||||||
proc `$`*[E](x: UserId | Join | Session | NickClaim | NickClaimResponse |
|
|
||||||
UserInfo |
|
|
||||||
Says |
|
|
||||||
NickConflict): string =
|
|
||||||
`$`(toPreserve(x, E))
|
`$`(toPreserve(x, E))
|
||||||
|
|
||||||
proc `encode`*[E](x: UserId | Join | Session | NickClaim | NickClaimResponse |
|
proc encode*[E](x: Join[E] | Session[E] | NickClaim[E]): seq[byte] =
|
||||||
UserInfo |
|
|
||||||
Says |
|
|
||||||
NickConflict): seq[byte] =
|
|
||||||
encode(toPreserve(x, E))
|
encode(toPreserve(x, E))
|
||||||
|
|
||||||
|
proc `$`*(x: UserId | NickConflict | NickClaimResponse | UserInfo | Says): string =
|
||||||
|
`$`(toPreserve(x))
|
||||||
|
|
||||||
|
proc encode*(x: UserId | NickConflict | NickClaimResponse | UserInfo | Says): seq[
|
||||||
|
byte] =
|
||||||
|
encode(toPreserve(x))
|
||||||
|
|
|
@ -3,119 +3,47 @@ import
|
||||||
std/typetraits, preserves
|
std/typetraits, preserves
|
||||||
|
|
||||||
type
|
type
|
||||||
RequireService*[E = void] {.record: "require-service".} = ref object ## ``<require-service @serviceName any>``
|
ServiceStarted*[E] {.preservesRecord: "service-started".} = ref object
|
||||||
`serviceName`*: Preserve[E]
|
`serviceName`*: Preserve[E]
|
||||||
|
|
||||||
RunService*[E = void] {.record: "run-service".} = ref object ## ``<run-service @serviceName any>``
|
ServiceMilestone*[E] {.preservesRecord: "service-milestone".} = ref object
|
||||||
`serviceName`*: Preserve[E]
|
|
||||||
|
|
||||||
ServiceStarted*[E = void] {.record: "service-started".} = ref object ## ``<service-started @serviceName any>``
|
|
||||||
`serviceName`*: Preserve[E]
|
|
||||||
|
|
||||||
ServiceRunning*[E = void] {.record: "service-running".} = ref object ## ``<service-running @serviceName any>``
|
|
||||||
`serviceName`*: Preserve[E]
|
|
||||||
|
|
||||||
ServiceDependency*[E = void] {.record: "depends-on".} = ref object ## ``<depends-on @depender any @dependee Dependee>``
|
|
||||||
`depender`*: Preserve[E]
|
|
||||||
`dependee`*: Dependee[E]
|
|
||||||
|
|
||||||
DependeeKind* {.pure.} = enum
|
|
||||||
`Servicestarted`, `Servicerunning`
|
|
||||||
Dependee*[E = void] = ref object ## ``/ ServiceStarted / ServiceRunning``
|
|
||||||
case kind*: DependeeKind
|
|
||||||
of DependeeKind.`Servicestarted`:
|
|
||||||
`servicestarted`*: ServiceStarted[E]
|
|
||||||
|
|
||||||
of DependeeKind.`Servicerunning`:
|
|
||||||
`servicerunning`*: ServiceRunning[E]
|
|
||||||
|
|
||||||
|
|
||||||
ServiceMilestone*[E = void] {.record: "service-milestone".} = ref object ## ``<service-milestone @serviceName any @milestone any>``
|
|
||||||
`serviceName`*: Preserve[E]
|
`serviceName`*: Preserve[E]
|
||||||
`milestone`*: Preserve[E]
|
`milestone`*: Preserve[E]
|
||||||
|
|
||||||
proc `requireService`*[E = void](`serviceName`: Preserve[E]): Preserve[E] =
|
RequireService*[E] {.preservesRecord: "require-service".} = ref object
|
||||||
## Preserves constructor for ``RequireService``.
|
`serviceName`*: Preserve[E]
|
||||||
initRecord[E](symbol[E]("require-service"), toPreserve(`serviceName`, E))
|
|
||||||
|
|
||||||
proc toPreserveHook*(`requireservice`: RequireService; E: typedesc): Preserve[E] =
|
DependeeKind* {.pure.} = enum
|
||||||
initRecord[E](symbol[E]("require-service"),
|
`ServiceStarted`, `ServiceRunning`
|
||||||
toPreserve(`requireservice`.`serviceName`, E))
|
`Dependee`*[E] {.preservesOr.} = ref object
|
||||||
|
case orKind*: DependeeKind
|
||||||
|
of DependeeKind.`ServiceStarted`:
|
||||||
|
`servicestarted`*: ServiceStarted[E]
|
||||||
|
|
||||||
proc `runService`*[E = void](`serviceName`: Preserve[E]): Preserve[E] =
|
of DependeeKind.`ServiceRunning`:
|
||||||
## Preserves constructor for ``RunService``.
|
`servicerunning`*: ServiceRunning[E]
|
||||||
initRecord[E](symbol[E]("run-service"), toPreserve(`serviceName`, E))
|
|
||||||
|
|
||||||
proc toPreserveHook*(`runservice`: RunService; E: typedesc): Preserve[E] =
|
|
||||||
initRecord[E](symbol[E]("run-service"),
|
|
||||||
toPreserve(`runservice`.`serviceName`, E))
|
|
||||||
|
|
||||||
proc `serviceStarted`*[E = void](`serviceName`: Preserve[E]): Preserve[E] =
|
RunService*[E] {.preservesRecord: "run-service".} = ref object
|
||||||
## Preserves constructor for ``ServiceStarted``.
|
`serviceName`*: Preserve[E]
|
||||||
initRecord[E](symbol[E]("service-started"), toPreserve(`serviceName`, E))
|
|
||||||
|
|
||||||
proc toPreserveHook*(`servicestarted`: ServiceStarted; E: typedesc): Preserve[E] =
|
ServiceRunning*[E] {.preservesRecord: "service-running".} = ref object
|
||||||
initRecord[E](symbol[E]("service-started"),
|
`serviceName`*: Preserve[E]
|
||||||
toPreserve(`servicestarted`.`serviceName`, E))
|
|
||||||
|
|
||||||
proc `serviceRunning`*[E = void](`serviceName`: Preserve[E]): Preserve[E] =
|
ServiceDependency*[E] {.preservesRecord: "depends-on".} = ref object
|
||||||
## Preserves constructor for ``ServiceRunning``.
|
`depender`*: Preserve[E]
|
||||||
initRecord[E](symbol[E]("service-running"), toPreserve(`serviceName`, E))
|
`dependee`*: Dependee[E]
|
||||||
|
|
||||||
proc toPreserveHook*(`servicerunning`: ServiceRunning; E: typedesc): Preserve[E] =
|
proc `$`*[E](x: ServiceStarted[E] | ServiceMilestone[E] | RequireService[E] |
|
||||||
initRecord[E](symbol[E]("service-running"),
|
|
||||||
toPreserve(`servicerunning`.`serviceName`, E))
|
|
||||||
|
|
||||||
proc `serviceDependency`*[E = void](`depender`: Preserve[E];
|
|
||||||
`dependee`: Dependee | Preserve[E]): Preserve[
|
|
||||||
E] =
|
|
||||||
## Preserves constructor for ``ServiceDependency``.
|
|
||||||
initRecord[E](symbol[E]("depends-on"), toPreserve(`depender`, E),
|
|
||||||
toPreserve(`dependee`, E))
|
|
||||||
|
|
||||||
proc toPreserveHook*(`servicedependency`: ServiceDependency; E: typedesc): Preserve[
|
|
||||||
E] =
|
|
||||||
initRecord[E](symbol[E]("depends-on"),
|
|
||||||
toPreserve(`servicedependency`.`depender`, E),
|
|
||||||
toPreserve(`servicedependency`.`dependee`, E))
|
|
||||||
|
|
||||||
proc toPreserveHook*(v: Dependee; E: typedesc): Preserve[E] =
|
|
||||||
case v.kind
|
|
||||||
of DependeeKind.`Servicestarted`:
|
|
||||||
toPreserve(v.`servicestarted`, E)
|
|
||||||
of DependeeKind.`Servicerunning`:
|
|
||||||
toPreserve(v.`servicerunning`, E)
|
|
||||||
|
|
||||||
proc fromPreserveHook*[E](v: var Dependee; pr: Preserve[E]): bool =
|
|
||||||
if isRecord(pr) and pr.label.isSymbol("ServiceStarted"):
|
|
||||||
v = Dependee(kind: DependeeKind.`Servicestarted`)
|
|
||||||
result = fromPreserve(v.`servicestarted`, pr)
|
|
||||||
elif isRecord(pr) and pr.label.isSymbol("ServiceRunning"):
|
|
||||||
v = Dependee(kind: DependeeKind.`Servicerunning`)
|
|
||||||
result = fromPreserve(v.`servicerunning`, pr)
|
|
||||||
|
|
||||||
proc `serviceMilestone`*[E = void](`serviceName`: Preserve[E];
|
|
||||||
`milestone`: Preserve[E]): Preserve[E] =
|
|
||||||
## Preserves constructor for ``ServiceMilestone``.
|
|
||||||
initRecord[E](symbol[E]("service-milestone"), toPreserve(`serviceName`, E),
|
|
||||||
toPreserve(`milestone`, E))
|
|
||||||
|
|
||||||
proc toPreserveHook*(`servicemilestone`: ServiceMilestone; E: typedesc): Preserve[
|
|
||||||
E] =
|
|
||||||
initRecord[E](symbol[E]("service-milestone"),
|
|
||||||
toPreserve(`servicemilestone`.`serviceName`, E),
|
|
||||||
toPreserve(`servicemilestone`.`milestone`, E))
|
|
||||||
|
|
||||||
proc `$`*[E](x: RequireService[E] | RunService[E] | ServiceStarted[E] |
|
|
||||||
ServiceRunning[E] |
|
|
||||||
ServiceDependency[E] |
|
|
||||||
Dependee[E] |
|
Dependee[E] |
|
||||||
ServiceMilestone[E]): string =
|
RunService[E] |
|
||||||
|
ServiceRunning[E] |
|
||||||
|
ServiceDependency[E]): string =
|
||||||
`$`(toPreserve(x, E))
|
`$`(toPreserve(x, E))
|
||||||
|
|
||||||
proc `encode`*[E](x: RequireService[E] | RunService[E] | ServiceStarted[E] |
|
proc encode*[E](x: ServiceStarted[E] | ServiceMilestone[E] | RequireService[E] |
|
||||||
ServiceRunning[E] |
|
|
||||||
ServiceDependency[E] |
|
|
||||||
Dependee[E] |
|
Dependee[E] |
|
||||||
ServiceMilestone[E]): seq[byte] =
|
RunService[E] |
|
||||||
|
ServiceRunning[E] |
|
||||||
|
ServiceDependency[E]): seq[byte] =
|
||||||
encode(toPreserve(x, E))
|
encode(toPreserve(x, E))
|
||||||
|
|
|
@ -3,31 +3,15 @@ import
|
||||||
std/typetraits, preserves
|
std/typetraits, preserves
|
||||||
|
|
||||||
type
|
type
|
||||||
Present* {.record: "Present".} = ref object ## ``<Present @username string>``
|
Says* {.preservesRecord: "Says".} = object
|
||||||
`username`*: string
|
|
||||||
|
|
||||||
Says* {.record: "Says".} = ref object ## ``<Says @who string @what string>``
|
|
||||||
`who`*: string
|
`who`*: string
|
||||||
`what`*: string
|
`what`*: string
|
||||||
|
|
||||||
proc `present`*[E = void](`username`: string | Preserve[E]): Preserve[E] =
|
Present* {.preservesRecord: "Present".} = object
|
||||||
## Preserves constructor for ``Present``.
|
`username`*: string
|
||||||
initRecord[E](symbol[E]("Present"), toPreserve(`username`, E))
|
|
||||||
|
|
||||||
proc toPreserveHook*(`present`: Present; E: typedesc): Preserve[E] =
|
proc `$`*(x: Says | Present): string =
|
||||||
initRecord[E](symbol[E]("Present"), toPreserve(`present`.`username`, E))
|
`$`(toPreserve(x))
|
||||||
|
|
||||||
proc `says`*[E = void](`who`: string | Preserve[E]; `what`: string | Preserve[E]): Preserve[
|
proc encode*(x: Says | Present): seq[byte] =
|
||||||
E] =
|
encode(toPreserve(x))
|
||||||
## Preserves constructor for ``Says``.
|
|
||||||
initRecord[E](symbol[E]("Says"), toPreserve(`who`, E), toPreserve(`what`, E))
|
|
||||||
|
|
||||||
proc toPreserveHook*(`says`: Says; E: typedesc): Preserve[E] =
|
|
||||||
initRecord[E](symbol[E]("Says"), toPreserve(`says`.`who`, E),
|
|
||||||
toPreserve(`says`.`what`, E))
|
|
||||||
|
|
||||||
proc `$`*[E](x: Present | Says): string =
|
|
||||||
`$`(toPreserve(x, E))
|
|
||||||
|
|
||||||
proc `encode`*[E](x: Present | Says): seq[byte] =
|
|
||||||
encode(toPreserve(x, E))
|
|
||||||
|
|
|
@ -3,266 +3,119 @@ import
|
||||||
std/typetraits, preserves
|
std/typetraits, preserves
|
||||||
|
|
||||||
type
|
type
|
||||||
StreamConnection*[E = void] {.record: "stream-connection".} = ref object ## ``<stream-connection @source #!Source @sink #!Sink @spec any>``
|
CreditAmountKind* {.pure.} = enum
|
||||||
`source`*: Source[E]
|
`count`, `unbounded`
|
||||||
`sink`*: Sink[E]
|
CreditAmountCount* = BiggestInt
|
||||||
`spec`*: Preserve[E]
|
`CreditAmount`* {.preservesOr.} = object
|
||||||
|
case orKind*: CreditAmountKind
|
||||||
|
of CreditAmountKind.`count`:
|
||||||
|
`count`*: CreditAmountCount
|
||||||
|
|
||||||
StreamListenerReady*[E = void] {.record: "stream-listener-ready".} = ref object ## ``<stream-listener-ready @spec any>``
|
of CreditAmountKind.`unbounded`:
|
||||||
`spec`*: Preserve[E]
|
`unbounded`* {.preservesLiteral: "unbounded".}: bool
|
||||||
|
|
||||||
StreamListenerError*[E = void] {.record: "stream-listener-error".} = ref object ## ``<stream-listener-error @spec any @message string>``
|
|
||||||
|
StreamError* {.preservesRecord: "error".} = object
|
||||||
|
`message`*: string
|
||||||
|
|
||||||
|
StreamListenerError*[E] {.preservesRecord: "stream-listener-error".} = ref object
|
||||||
`spec`*: Preserve[E]
|
`spec`*: Preserve[E]
|
||||||
`message`*: string
|
`message`*: string
|
||||||
|
|
||||||
StreamError* {.record: "error".} = ref object ## ``<error @message string>``
|
StreamConnection*[E] {.preservesRecord: "stream-connection".} = ref object
|
||||||
`message`*: string
|
`source`*: Preserve[E]
|
||||||
|
`sink`*: Preserve[E]
|
||||||
|
`spec`*: Preserve[E]
|
||||||
|
|
||||||
|
`LineMode`* {.preservesOr.} = enum
|
||||||
|
`lf`, `crlf`
|
||||||
SourceKind* {.pure.} = enum
|
SourceKind* {.pure.} = enum
|
||||||
`sink`, `Streamerror`, `credit`
|
`sink`, `StreamError`, `credit`
|
||||||
Sourcesink*[E = void] {.record: "sink".} = ref object
|
SourceSink*[E] {.preservesRecord: "sink".} = ref object
|
||||||
`controller`*: Sink[E]
|
`controller`*: Preserve[E]
|
||||||
|
|
||||||
Sourcecredit*[E = void] {.record: "credit".} = ref object
|
SourceCredit*[E] {.preservesRecord: "credit".} = ref object
|
||||||
`amount`*: CreditAmount
|
`amount`*: CreditAmount
|
||||||
`mode`*: Mode[E]
|
`mode`*: Mode[E]
|
||||||
|
|
||||||
Source*[E = void] = ref object ## ``/ <sink @controller #!Sink> / StreamError / <credit @amount CreditAmount @mode Mode>``
|
`Source`*[E] {.preservesOr.} = ref object
|
||||||
case kind*: SourceKind
|
case orKind*: SourceKind
|
||||||
of SourceKind.`sink`:
|
of SourceKind.`sink`:
|
||||||
`sink`*: Preserve[E]
|
`sink`*: SourceSink[E]
|
||||||
|
|
||||||
of SourceKind.`Streamerror`:
|
of SourceKind.`StreamError`:
|
||||||
`streamerror`*: StreamError
|
`streamerror`*: StreamError
|
||||||
|
|
||||||
of SourceKind.`credit`:
|
of SourceKind.`credit`:
|
||||||
`credit`*: Sourcecredit[E]
|
`credit`*: SourceCredit[E]
|
||||||
|
|
||||||
|
|
||||||
SinkKind* {.pure.} = enum
|
SinkKind* {.pure.} = enum
|
||||||
`source`, `Streamerror`, `data`, `eof`
|
`source`, `StreamError`, `data`, `eof`
|
||||||
Sinksource*[E = void] {.record: "source".} = ref object
|
SinkSource*[E] {.preservesRecord: "source".} = ref object
|
||||||
`controller`*: Source[E]
|
`controller`*: Preserve[E]
|
||||||
|
|
||||||
Sinkdata*[E = void] {.record: "data".} = ref object
|
SinkData*[E] {.preservesRecord: "data".} = ref object
|
||||||
`payload`*: Preserve[E]
|
`payload`*: Preserve[E]
|
||||||
`mode`*: Mode[E]
|
`mode`*: Mode[E]
|
||||||
|
|
||||||
Sinkeof* {.record: "eof".} = object
|
SinkEof* {.preservesRecord: "eof".} = object
|
||||||
discard
|
|
||||||
|
|
||||||
Sink*[E = void] = ref object ## ``/ <source @controller #!Source> / StreamError / <data @payload any @mode Mode> / <eof>``
|
`Sink`*[E] {.preservesOr.} = ref object
|
||||||
case kind*: SinkKind
|
case orKind*: SinkKind
|
||||||
of SinkKind.`source`:
|
of SinkKind.`source`:
|
||||||
`source`*: Preserve[E]
|
`source`*: SinkSource[E]
|
||||||
|
|
||||||
of SinkKind.`Streamerror`:
|
of SinkKind.`StreamError`:
|
||||||
`streamerror`*: StreamError
|
`streamerror`*: StreamError
|
||||||
|
|
||||||
of SinkKind.`data`:
|
of SinkKind.`data`:
|
||||||
`data`*: Sinkdata[E]
|
`data`*: SinkData[E]
|
||||||
|
|
||||||
of SinkKind.`eof`:
|
of SinkKind.`eof`:
|
||||||
`eof`*: Sinkeof
|
`eof`*: SinkEof
|
||||||
|
|
||||||
|
|
||||||
CreditamountKind* {.pure.} = enum
|
StreamListenerReady*[E] {.preservesRecord: "stream-listener-ready".} = ref object
|
||||||
`count`, `unbounded`
|
`spec`*: Preserve[E]
|
||||||
CreditAmountcount* = BiggestInt
|
|
||||||
CreditAmountunbounded* = string
|
|
||||||
CreditAmount* = ref object ## ``/ @count int / =<<lit>unbounded>``
|
|
||||||
case kind*: CreditamountKind
|
|
||||||
of CreditamountKind.`count`:
|
|
||||||
`count`*: CreditAmountcount
|
|
||||||
|
|
||||||
of CreditamountKind.`unbounded`:
|
|
||||||
discard
|
|
||||||
|
|
||||||
|
|
||||||
ModeKind* {.pure.} = enum
|
ModeKind* {.pure.} = enum
|
||||||
`bytes`, `lines`, `packet`, `object`
|
`bytes`, `lines`, `packet`, `object`
|
||||||
Modebytes* = string
|
ModePacket* {.preservesRecord: "packet".} = object
|
||||||
Modepacket* {.record: "packet".} = ref object
|
|
||||||
`size`*: BiggestInt
|
`size`*: BiggestInt
|
||||||
|
|
||||||
Modeobject*[E = void] {.record: "object".} = ref object
|
ModeObject*[E] {.preservesRecord: "object".} = ref object
|
||||||
`description`*: Preserve[E]
|
`description`*: Preserve[E]
|
||||||
|
|
||||||
Mode*[E = void] = ref object ## ``/ =<<lit>bytes> / LineMode / <packet @size int> / <object @description any>``
|
`Mode`*[E] {.preservesOr.} = ref object
|
||||||
case kind*: ModeKind
|
case orKind*: ModeKind
|
||||||
of ModeKind.`bytes`:
|
of ModeKind.`bytes`:
|
||||||
discard
|
`bytes`* {.preservesLiteral: "bytes".}: bool
|
||||||
|
|
||||||
of ModeKind.`lines`:
|
of ModeKind.`lines`:
|
||||||
`lines`*: LineMode
|
`lines`*: LineMode
|
||||||
|
|
||||||
of ModeKind.`packet`:
|
of ModeKind.`packet`:
|
||||||
`packet`*: BiggestInt
|
`packet`*: ModePacket
|
||||||
|
|
||||||
of ModeKind.`object`:
|
of ModeKind.`object`:
|
||||||
`object`*: Preserve[E]
|
`object`*: ModeObject[E]
|
||||||
|
|
||||||
|
|
||||||
LineMode* {.pure.} = enum ## ``/ =<<lit>lf> / =<<lit>crlf>``
|
proc `$`*[E](x: StreamListenerError[E] | StreamConnection[E] | Source[E] |
|
||||||
`lf`, `crlf`
|
|
||||||
proc `streamConnection`*[E = void](`source`: Preserve[E]; `sink`: Preserve[E];
|
|
||||||
`spec`: Preserve[E]): Preserve[E] =
|
|
||||||
## Preserves constructor for ``StreamConnection``.
|
|
||||||
initRecord[E](symbol[E]("stream-connection"), toPreserve(`source`, E),
|
|
||||||
toPreserve(`sink`, E), toPreserve(`spec`, E))
|
|
||||||
|
|
||||||
proc toPreserveHook*(`streamconnection`: StreamConnection; E: typedesc): Preserve[
|
|
||||||
E] =
|
|
||||||
initRecord[E](symbol[E]("stream-connection"),
|
|
||||||
toPreserve(`streamconnection`.`source`, E),
|
|
||||||
toPreserve(`streamconnection`.`sink`, E),
|
|
||||||
toPreserve(`streamconnection`.`spec`, E))
|
|
||||||
|
|
||||||
proc `streamListenerReady`*[E = void](`spec`: Preserve[E]): Preserve[E] =
|
|
||||||
## Preserves constructor for ``StreamListenerReady``.
|
|
||||||
initRecord[E](symbol[E]("stream-listener-ready"), toPreserve(`spec`, E))
|
|
||||||
|
|
||||||
proc toPreserveHook*(`streamlistenerready`: StreamListenerReady; E: typedesc): Preserve[
|
|
||||||
E] =
|
|
||||||
initRecord[E](symbol[E]("stream-listener-ready"),
|
|
||||||
toPreserve(`streamlistenerready`.`spec`, E))
|
|
||||||
|
|
||||||
proc `streamListenerError`*[E = void](`spec`: Preserve[E];
|
|
||||||
`message`: string | Preserve[E]): Preserve[
|
|
||||||
E] =
|
|
||||||
## Preserves constructor for ``StreamListenerError``.
|
|
||||||
initRecord[E](symbol[E]("stream-listener-error"), toPreserve(`spec`, E),
|
|
||||||
toPreserve(`message`, E))
|
|
||||||
|
|
||||||
proc toPreserveHook*(`streamlistenererror`: StreamListenerError; E: typedesc): Preserve[
|
|
||||||
E] =
|
|
||||||
initRecord[E](symbol[E]("stream-listener-error"),
|
|
||||||
toPreserve(`streamlistenererror`.`spec`, E),
|
|
||||||
toPreserve(`streamlistenererror`.`message`, E))
|
|
||||||
|
|
||||||
proc `streamError`*[E = void](`message`: string | Preserve[E]): Preserve[E] =
|
|
||||||
## Preserves constructor for ``StreamError``.
|
|
||||||
initRecord[E](symbol[E]("error"), toPreserve(`message`, E))
|
|
||||||
|
|
||||||
proc toPreserveHook*(`streamerror`: StreamError; E: typedesc): Preserve[E] =
|
|
||||||
initRecord[E](symbol[E]("error"), toPreserve(`streamerror`.`message`, E))
|
|
||||||
|
|
||||||
proc toPreserveHook*(v: Source; E: typedesc): Preserve[E] =
|
|
||||||
case v.kind
|
|
||||||
of SourceKind.`sink`:
|
|
||||||
toPreserve(v.`sink`, E)
|
|
||||||
of SourceKind.`Streamerror`:
|
|
||||||
toPreserve(v.`streamerror`, E)
|
|
||||||
of SourceKind.`credit`:
|
|
||||||
toPreserve(v.`credit`, E)
|
|
||||||
|
|
||||||
proc fromPreserveHook*[E](v: var Source; pr: Preserve[E]): bool =
|
|
||||||
if isRecord(pr) and pr.label.isSymbol("sink"):
|
|
||||||
v = Source(kind: SourceKind.`sink`)
|
|
||||||
result = fromPreserve(v.`sink`, pr)
|
|
||||||
elif isRecord(pr) and pr.label.isSymbol("StreamError"):
|
|
||||||
v = Source(kind: SourceKind.`Streamerror`)
|
|
||||||
result = fromPreserve(v.`streamerror`, pr)
|
|
||||||
elif isRecord(pr) and pr.label.isSymbol("credit"):
|
|
||||||
v = Source(kind: SourceKind.`credit`)
|
|
||||||
result = fromPreserve(v.`credit`, pr)
|
|
||||||
|
|
||||||
proc toPreserveHook*(v: Sink; E: typedesc): Preserve[E] =
|
|
||||||
case v.kind
|
|
||||||
of SinkKind.`source`:
|
|
||||||
toPreserve(v.`source`, E)
|
|
||||||
of SinkKind.`Streamerror`:
|
|
||||||
toPreserve(v.`streamerror`, E)
|
|
||||||
of SinkKind.`data`:
|
|
||||||
toPreserve(v.`data`, E)
|
|
||||||
of SinkKind.`eof`:
|
|
||||||
toPreserve(v.`eof`, E)
|
|
||||||
|
|
||||||
proc fromPreserveHook*[E](v: var Sink; pr: Preserve[E]): bool =
|
|
||||||
if isRecord(pr) and pr.label.isSymbol("source"):
|
|
||||||
v = Sink(kind: SinkKind.`source`)
|
|
||||||
result = fromPreserve(v.`source`, pr)
|
|
||||||
elif isRecord(pr) and pr.label.isSymbol("StreamError"):
|
|
||||||
v = Sink(kind: SinkKind.`Streamerror`)
|
|
||||||
result = fromPreserve(v.`streamerror`, pr)
|
|
||||||
elif isRecord(pr) and pr.label.isSymbol("data"):
|
|
||||||
v = Sink(kind: SinkKind.`data`)
|
|
||||||
result = fromPreserve(v.`data`, pr)
|
|
||||||
elif isRecord(pr) and pr.label.isSymbol("eof"):
|
|
||||||
v = Sink(kind: SinkKind.`eof`)
|
|
||||||
result = fromPreserve(v.`eof`, pr)
|
|
||||||
|
|
||||||
proc toPreserveHook*(v: CreditAmount; E: typedesc): Preserve[E] =
|
|
||||||
case v.kind
|
|
||||||
of CreditAmountKind.`count`:
|
|
||||||
toPreserve(v.`count`, E)
|
|
||||||
of CreditAmountKind.`unbounded`:
|
|
||||||
Preserve[E](kind: pkSymbol, symbol: "unbounded")
|
|
||||||
|
|
||||||
proc fromPreserveHook*[E](v: var CreditAmount; pr: Preserve[E]): bool =
|
|
||||||
if false:
|
|
||||||
discard
|
|
||||||
elif pr.kind == pkSymbol and pr.symbol == "unbounded":
|
|
||||||
v = CreditAmount(kind: CreditAmountKind.`unbounded`)
|
|
||||||
result = true
|
|
||||||
|
|
||||||
proc toPreserveHook*(v: Mode; E: typedesc): Preserve[E] =
|
|
||||||
case v.kind
|
|
||||||
of ModeKind.`bytes`:
|
|
||||||
Preserve[E](kind: pkSymbol, symbol: "bytes")
|
|
||||||
of ModeKind.`lines`:
|
|
||||||
toPreserve(v.`lines`, E)
|
|
||||||
of ModeKind.`packet`:
|
|
||||||
toPreserve(v.`packet`, E)
|
|
||||||
of ModeKind.`object`:
|
|
||||||
toPreserve(v.`object`, E)
|
|
||||||
|
|
||||||
proc fromPreserveHook*[E](v: var Mode; pr: Preserve[E]): bool =
|
|
||||||
if pr.kind == pkSymbol and pr.symbol == "bytes":
|
|
||||||
v = Mode(kind: ModeKind.`bytes`)
|
|
||||||
result = true
|
|
||||||
elif false: ## snkOr - / =<<lit>lf> / =<<lit>crlf>
|
|
||||||
discard
|
|
||||||
elif isRecord(pr) and pr.label.isSymbol("packet"):
|
|
||||||
v = Mode(kind: ModeKind.`packet`)
|
|
||||||
result = fromPreserve(v.`packet`, pr)
|
|
||||||
elif isRecord(pr) and pr.label.isSymbol("object"):
|
|
||||||
v = Mode(kind: ModeKind.`object`)
|
|
||||||
result = fromPreserve(v.`object`, pr)
|
|
||||||
|
|
||||||
proc toPreserveHook*(v: LineMode; E: typedesc): Preserve[E] =
|
|
||||||
case v
|
|
||||||
of LineMode.`lf`:
|
|
||||||
symbol[E]("lf")
|
|
||||||
of LineMode.`crlf`:
|
|
||||||
symbol[E]("crlf")
|
|
||||||
|
|
||||||
proc fromPreserveHook*[E](v: var LineMode; pr: Preserve[E]): bool =
|
|
||||||
if isSymbol(pr):
|
|
||||||
case pr.symbol
|
|
||||||
of "lf":
|
|
||||||
v = LineMode.`lf`
|
|
||||||
result = true
|
|
||||||
of "crlf":
|
|
||||||
v = LineMode.`crlf`
|
|
||||||
result = true
|
|
||||||
|
|
||||||
proc `$`*[E](x: StreamConnection[E] | StreamListenerReady[E] |
|
|
||||||
StreamListenerError[E] |
|
|
||||||
StreamError |
|
|
||||||
Source[E] |
|
|
||||||
Sink[E] |
|
Sink[E] |
|
||||||
CreditAmount |
|
StreamListenerReady[E] |
|
||||||
Mode[E] |
|
Mode[E]): string =
|
||||||
LineMode): string =
|
|
||||||
`$`(toPreserve(x, E))
|
`$`(toPreserve(x, E))
|
||||||
|
|
||||||
proc `encode`*[E](x: StreamConnection[E] | StreamListenerReady[E] |
|
proc encode*[E](x: StreamListenerError[E] | StreamConnection[E] | Source[E] |
|
||||||
StreamListenerError[E] |
|
|
||||||
StreamError |
|
|
||||||
Source[E] |
|
|
||||||
Sink[E] |
|
Sink[E] |
|
||||||
CreditAmount |
|
StreamListenerReady[E] |
|
||||||
Mode[E] |
|
Mode[E]): seq[byte] =
|
||||||
LineMode): seq[byte] =
|
|
||||||
encode(toPreserve(x, E))
|
encode(toPreserve(x, E))
|
||||||
|
|
||||||
|
proc `$`*(x: CreditAmount | StreamError): string =
|
||||||
|
`$`(toPreserve(x))
|
||||||
|
|
||||||
|
proc encode*(x: CreditAmount | StreamError): seq[byte] =
|
||||||
|
encode(toPreserve(x))
|
||||||
|
|
|
@ -3,16 +3,76 @@ import
|
||||||
std/typetraits, preserves, std/tables, std/tables
|
std/typetraits, preserves, std/tables, std/tables
|
||||||
|
|
||||||
type
|
type
|
||||||
SturdyRef*[E = void] {.record: "ref".} = ref object ## ``<ref @oid any @caveatChain [ Attenuation ... ] @sig bytes>``
|
CRec*[E] {.preservesRecord: "rec".} = ref object
|
||||||
`oid`*: Preserve[E]
|
`label`*: Preserve[E]
|
||||||
`caveatChain`*: seq[Attenuation[E]]
|
`arity`*: BiggestInt
|
||||||
`sig`*: seq[byte]
|
|
||||||
|
PCompound*[E] {.preservesRecord: "compound".} = ref object
|
||||||
|
`ctor`*: ConstructorSpec[E]
|
||||||
|
`members`*: PCompoundMembers[E]
|
||||||
|
|
||||||
|
ConstructorSpecKind* {.pure.} = enum
|
||||||
|
`CRec`, `CArr`, `CDict`
|
||||||
|
`ConstructorSpec`*[E] {.preservesOr.} = ref object
|
||||||
|
case orKind*: ConstructorSpecKind
|
||||||
|
of ConstructorSpecKind.`CRec`:
|
||||||
|
`crec`*: CRec[E]
|
||||||
|
|
||||||
|
of ConstructorSpecKind.`CArr`:
|
||||||
|
`carr`*: CArr
|
||||||
|
|
||||||
|
of ConstructorSpecKind.`CDict`:
|
||||||
|
`cdict`*: CDict
|
||||||
|
|
||||||
|
|
||||||
|
PAnd*[E] {.preservesRecord: "and".} = ref object
|
||||||
|
`patterns`*: seq[Pattern[E]]
|
||||||
|
|
||||||
|
Rewrite*[E] {.preservesRecord: "rewrite".} = ref object
|
||||||
|
`pattern`*: Pattern[E]
|
||||||
|
`template`*: Template[E]
|
||||||
|
|
||||||
|
TCompoundMembers*[E] = Table[Preserve[E], Template[E]]
|
||||||
|
TRef* {.preservesRecord: "ref".} = object
|
||||||
|
`binding`*: BiggestInt
|
||||||
|
|
||||||
|
PBind*[E] {.preservesRecord: "bind".} = ref object
|
||||||
|
`pattern`*: Pattern[E]
|
||||||
|
|
||||||
|
Lit*[E] {.preservesRecord: "lit".} = ref object
|
||||||
|
`value`*: Preserve[E]
|
||||||
|
|
||||||
|
TCompound*[E] {.preservesRecord: "compound".} = ref object
|
||||||
|
`ctor`*: ConstructorSpec[E]
|
||||||
|
`members`*: TCompoundMembers[E]
|
||||||
|
|
||||||
|
`PAtom`* {.preservesOr.} = enum
|
||||||
|
`Boolean`, `Float`, `Double`, `SignedInteger`, `String`, `ByteString`,
|
||||||
|
`Symbol`
|
||||||
|
Attenuation*[E] = seq[Caveat[E]]
|
||||||
|
PDiscard* {.preservesRecord: "_".} = object
|
||||||
|
|
||||||
|
TemplateKind* {.pure.} = enum
|
||||||
|
`TAttenuate`, `TRef`, `Lit`, `TCompound`
|
||||||
|
`Template`*[E] {.preservesOr.} = ref object
|
||||||
|
case orKind*: TemplateKind
|
||||||
|
of TemplateKind.`TAttenuate`:
|
||||||
|
`tattenuate`*: TAttenuate[E]
|
||||||
|
|
||||||
|
of TemplateKind.`TRef`:
|
||||||
|
`tref`*: TRef
|
||||||
|
|
||||||
|
of TemplateKind.`Lit`:
|
||||||
|
`lit`*: Lit[E]
|
||||||
|
|
||||||
|
of TemplateKind.`TCompound`:
|
||||||
|
`tcompound`*: TCompound[E]
|
||||||
|
|
||||||
|
|
||||||
Attenuation*[E = void] = seq[Caveat[E]] ## ``[ Caveat ... ]``
|
|
||||||
CaveatKind* {.pure.} = enum
|
CaveatKind* {.pure.} = enum
|
||||||
`Rewrite`, `Alts`
|
`Rewrite`, `Alts`
|
||||||
Caveat*[E = void] = ref object ## ``/ Rewrite / Alts``
|
`Caveat`*[E] {.preservesOr.} = ref object
|
||||||
case kind*: CaveatKind
|
case orKind*: CaveatKind
|
||||||
of CaveatKind.`Rewrite`:
|
of CaveatKind.`Rewrite`:
|
||||||
`rewrite`*: Rewrite[E]
|
`rewrite`*: Rewrite[E]
|
||||||
|
|
||||||
|
@ -20,475 +80,116 @@ type
|
||||||
`alts`*: Alts[E]
|
`alts`*: Alts[E]
|
||||||
|
|
||||||
|
|
||||||
Rewrite*[E = void] {.record: "rewrite".} = ref object ## ``<rewrite @pattern Pattern @template Template>``
|
CArr* {.preservesRecord: "arr".} = object
|
||||||
`pattern`*: Pattern[E]
|
`arity`*: BiggestInt
|
||||||
`template`*: Template[E]
|
|
||||||
|
|
||||||
Alts*[E = void] {.record: "or".} = ref object ## ``<or @alternatives [ Rewrite ... ]>``
|
PCompoundMembers*[E] = Table[Preserve[E], Pattern[E]]
|
||||||
|
PNot*[E] {.preservesRecord: "not".} = ref object
|
||||||
|
`pattern`*: Pattern[E]
|
||||||
|
|
||||||
|
SturdyRef*[E] {.preservesRecord: "ref".} = ref object
|
||||||
|
`oid`*: Preserve[E]
|
||||||
|
`caveatChain`*: seq[Attenuation[E]]
|
||||||
|
`sig`*: seq[byte]
|
||||||
|
|
||||||
|
WireRefKind* {.pure.} = enum
|
||||||
|
`mine`, `yours`
|
||||||
|
WireRefMine* {.preservesTuple.} = object
|
||||||
|
`data`* {.preservesLiteral: "0".}: bool
|
||||||
|
`oid`*: Oid
|
||||||
|
|
||||||
|
WireRefYours*[E] {.preservesTuple.} = ref object
|
||||||
|
`data`* {.preservesLiteral: "1".}: bool
|
||||||
|
`oid`*: Oid
|
||||||
|
`attenuation`* {.preservesTupleTail.}: seq[Caveat[E]]
|
||||||
|
|
||||||
|
`WireRef`*[E] {.preservesOr.} = ref object
|
||||||
|
case orKind*: WireRefKind
|
||||||
|
of WireRefKind.`mine`:
|
||||||
|
`mine`*: WireRefMine
|
||||||
|
|
||||||
|
of WireRefKind.`yours`:
|
||||||
|
`yours`*: WireRefYours[E]
|
||||||
|
|
||||||
|
|
||||||
|
TAttenuate*[E] {.preservesRecord: "attenuate".} = ref object
|
||||||
|
`template`*: Template[E]
|
||||||
|
`attenuation`*: Attenuation[E]
|
||||||
|
|
||||||
|
Oid* = BiggestInt
|
||||||
|
Alts*[E] {.preservesRecord: "or".} = ref object
|
||||||
`alternatives`*: seq[Rewrite[E]]
|
`alternatives`*: seq[Rewrite[E]]
|
||||||
|
|
||||||
Oid* = distinct BiggestInt ## ``int``
|
CDict* {.preservesRecord: "dict".} = object
|
||||||
WirerefKind* {.pure.} = enum
|
|
||||||
`mine`, `yours`
|
|
||||||
WireRefmine* = tuple[`0`: BiggestInt, `oid`: Oid]
|
|
||||||
WireRefyours*[E = void] = tuple[`1`: BiggestInt, `oid`: Oid,
|
|
||||||
`attenuation`: seq[Caveat[E]]]
|
|
||||||
WireRef*[E = void] = ref object ## ``/ @mine [0 @oid Oid] / @yours [1 @oid Oid @attenuation Caveat ...]``
|
|
||||||
case kind*: WirerefKind
|
|
||||||
of WirerefKind.`mine`:
|
|
||||||
`mine`*: WireRefmine
|
|
||||||
|
|
||||||
of WirerefKind.`yours`:
|
|
||||||
`yours`*: WireRefyours[E]
|
|
||||||
|
|
||||||
|
|
||||||
ConstructorspecKind* {.pure.} = enum
|
|
||||||
`Crec`, `Carr`, `Cdict`
|
|
||||||
ConstructorSpec*[E = void] = ref object ## ``/ CRec / CArr / CDict``
|
|
||||||
case kind*: ConstructorspecKind
|
|
||||||
of ConstructorspecKind.`Crec`:
|
|
||||||
`crec`*: CRec[E]
|
|
||||||
|
|
||||||
of ConstructorspecKind.`Carr`:
|
|
||||||
`carr`*: CArr
|
|
||||||
|
|
||||||
of ConstructorspecKind.`Cdict`:
|
|
||||||
`cdict`*: CDict
|
|
||||||
|
|
||||||
|
|
||||||
CRec*[E = void] {.record: "rec".} = ref object ## ``<rec @label any @arity int>``
|
|
||||||
`label`*: Preserve[E]
|
|
||||||
`arity`*: BiggestInt
|
|
||||||
|
|
||||||
CArr* {.record: "arr".} = ref object ## ``<arr @arity int>``
|
|
||||||
`arity`*: BiggestInt
|
|
||||||
|
|
||||||
CDict* {.record: "dict".} = object ## ``<dict>``
|
|
||||||
discard
|
|
||||||
|
|
||||||
Lit*[E = void] {.record: "lit".} = ref object ## ``<lit @value any>``
|
|
||||||
`value`*: Preserve[E]
|
|
||||||
|
|
||||||
PatternKind* {.pure.} = enum
|
PatternKind* {.pure.} = enum
|
||||||
`Pdiscard`, `Patom`, `Pembedded`, `Pbind`, `Pand`, `Pnot`, `Lit`,
|
`PDiscard`, `PAtom`, `PEmbedded`, `PBind`, `PAnd`, `PNot`, `Lit`,
|
||||||
`Pcompound`
|
`PCompound`
|
||||||
Pattern*[E = void] = ref object ## ``/ PDiscard / PAtom / PEmbedded / PBind / PAnd / PNot / Lit / PCompound``
|
`Pattern`*[E] {.preservesOr.} = ref object
|
||||||
case kind*: PatternKind
|
case orKind*: PatternKind
|
||||||
of PatternKind.`Pdiscard`:
|
of PatternKind.`PDiscard`:
|
||||||
`pdiscard`*: PDiscard
|
`pdiscard`*: PDiscard
|
||||||
|
|
||||||
of PatternKind.`Patom`:
|
of PatternKind.`PAtom`:
|
||||||
`patom`*: PAtom
|
`patom`*: PAtom
|
||||||
|
|
||||||
of PatternKind.`Pembedded`:
|
of PatternKind.`PEmbedded`:
|
||||||
discard
|
`pembedded`* {.preservesLiteral: "Embedded".}: bool
|
||||||
|
|
||||||
of PatternKind.`Pbind`:
|
of PatternKind.`PBind`:
|
||||||
`pbind`*: PBind[E]
|
`pbind`*: PBind[E]
|
||||||
|
|
||||||
of PatternKind.`Pand`:
|
of PatternKind.`PAnd`:
|
||||||
`pand`*: PAnd[E]
|
`pand`*: PAnd[E]
|
||||||
|
|
||||||
of PatternKind.`Pnot`:
|
of PatternKind.`PNot`:
|
||||||
`pnot`*: PNot[E]
|
`pnot`*: PNot[E]
|
||||||
|
|
||||||
of PatternKind.`Lit`:
|
of PatternKind.`Lit`:
|
||||||
`lit`*: Lit[E]
|
`lit`*: Lit[E]
|
||||||
|
|
||||||
of PatternKind.`Pcompound`:
|
of PatternKind.`PCompound`:
|
||||||
`pcompound`*: PCompound[E]
|
`pcompound`*: PCompound[E]
|
||||||
|
|
||||||
|
|
||||||
PDiscard* {.record: "_".} = object ## ``<_>``
|
proc `$`*[E](x: CRec[E] | PCompound[E] | ConstructorSpec[E] | PAnd[E] |
|
||||||
discard
|
Rewrite[E] |
|
||||||
|
TCompoundMembers[E] |
|
||||||
PAtom* {.pure.} = enum ## ``/ =<<lit>Boolean> / =<<lit>Float> / =<<lit>Double> / =<<lit>SignedInteger> / =<<lit>String> / =<<lit>ByteString> / =<<lit>Symbol>``
|
|
||||||
`Boolean`, `Float`, `Double`, `Signedinteger`, `String`, `Bytestring`,
|
|
||||||
`Symbol`
|
|
||||||
PBind*[E = void] {.record: "bind".} = ref object ## ``<bind @pattern Pattern>``
|
|
||||||
`pattern`*: Pattern[E]
|
|
||||||
|
|
||||||
PAnd*[E = void] {.record: "and".} = ref object ## ``<and @patterns [ Pattern ... ]>``
|
|
||||||
`patterns`*: seq[Pattern[E]]
|
|
||||||
|
|
||||||
PNot*[E = void] {.record: "not".} = ref object ## ``<not @pattern Pattern>``
|
|
||||||
`pattern`*: Pattern[E]
|
|
||||||
|
|
||||||
PCompound*[E = void] {.record: "compound".} = ref object ## ``<compound @ctor ConstructorSpec @members PCompoundMembers>``
|
|
||||||
`ctor`*: ConstructorSpec[E]
|
|
||||||
`members`*: PCompoundMembers[E]
|
|
||||||
|
|
||||||
PCompoundMembers*[E = void] = TableRef[Preserve[E], Pattern[E]] ## ``{any : Pattern ...:...}``
|
|
||||||
TemplateKind* {.pure.} = enum
|
|
||||||
`Tattenuate`, `Tref`, `Lit`, `Tcompound`
|
|
||||||
Template*[E = void] = ref object ## ``/ TAttenuate / TRef / Lit / TCompound``
|
|
||||||
case kind*: TemplateKind
|
|
||||||
of TemplateKind.`Tattenuate`:
|
|
||||||
`tattenuate`*: TAttenuate[E]
|
|
||||||
|
|
||||||
of TemplateKind.`Tref`:
|
|
||||||
`tref`*: TRef
|
|
||||||
|
|
||||||
of TemplateKind.`Lit`:
|
|
||||||
`lit`*: Lit[E]
|
|
||||||
|
|
||||||
of TemplateKind.`Tcompound`:
|
|
||||||
`tcompound`*: TCompound[E]
|
|
||||||
|
|
||||||
|
|
||||||
TAttenuate*[E = void] {.record: "attenuate".} = ref object ## ``<attenuate @template Template @attenuation Attenuation>``
|
|
||||||
`template`*: Template[E]
|
|
||||||
`attenuation`*: Attenuation[E]
|
|
||||||
|
|
||||||
TRef* {.record: "ref".} = ref object ## ``<ref @binding int>``
|
|
||||||
`binding`*: BiggestInt
|
|
||||||
|
|
||||||
TCompound*[E = void] {.record: "compound".} = ref object ## ``<compound @ctor ConstructorSpec @members TCompoundMembers>``
|
|
||||||
`ctor`*: ConstructorSpec[E]
|
|
||||||
`members`*: TCompoundMembers[E]
|
|
||||||
|
|
||||||
TCompoundMembers*[E = void] = TableRef[Preserve[E], Template[E]] ## ``{any : Template ...:...}``
|
|
||||||
proc `sturdyRef`*[E = void](`oid`: Preserve[E]; `caveatChain`: Preserve[E];
|
|
||||||
`sig`: seq[byte] | Preserve[E]): Preserve[E] =
|
|
||||||
## Preserves constructor for ``SturdyRef``.
|
|
||||||
initRecord[E](symbol[E]("ref"), toPreserve(`oid`, E),
|
|
||||||
toPreserve(`caveatChain`, E), toPreserve(`sig`, E))
|
|
||||||
|
|
||||||
proc toPreserveHook*(`sturdyref`: SturdyRef; E: typedesc): Preserve[E] =
|
|
||||||
initRecord[E](symbol[E]("ref"), toPreserve(`sturdyref`.`oid`, E),
|
|
||||||
toPreserve(`sturdyref`.`caveatChain`, E),
|
|
||||||
toPreserve(`sturdyref`.`sig`, E))
|
|
||||||
|
|
||||||
proc toPreserveHook*(v: Caveat; E: typedesc): Preserve[E] =
|
|
||||||
case v.kind
|
|
||||||
of CaveatKind.`Rewrite`:
|
|
||||||
toPreserve(v.`rewrite`, E)
|
|
||||||
of CaveatKind.`Alts`:
|
|
||||||
toPreserve(v.`alts`, E)
|
|
||||||
|
|
||||||
proc fromPreserveHook*[E](v: var Caveat; pr: Preserve[E]): bool =
|
|
||||||
if isRecord(pr) and pr.label.isSymbol("Rewrite"):
|
|
||||||
v = Caveat(kind: CaveatKind.`Rewrite`)
|
|
||||||
result = fromPreserve(v.`rewrite`, pr)
|
|
||||||
elif isRecord(pr) and pr.label.isSymbol("Alts"):
|
|
||||||
v = Caveat(kind: CaveatKind.`Alts`)
|
|
||||||
result = fromPreserve(v.`alts`, pr)
|
|
||||||
|
|
||||||
proc `rewrite`*[E = void](`pattern`: Pattern | Preserve[E];
|
|
||||||
`template`: Template | Preserve[E]): Preserve[E] =
|
|
||||||
## Preserves constructor for ``Rewrite``.
|
|
||||||
initRecord[E](symbol[E]("rewrite"), toPreserve(`pattern`, E),
|
|
||||||
toPreserve(`template`, E))
|
|
||||||
|
|
||||||
proc toPreserveHook*(`rewrite`: Rewrite; E: typedesc): Preserve[E] =
|
|
||||||
initRecord[E](symbol[E]("rewrite"), toPreserve(`rewrite`.`pattern`, E),
|
|
||||||
toPreserve(`rewrite`.`template`, E))
|
|
||||||
|
|
||||||
proc `alts`*[E = void](`alternatives`: Preserve[E]): Preserve[E] =
|
|
||||||
## Preserves constructor for ``Alts``.
|
|
||||||
initRecord[E](symbol[E]("or"), toPreserve(`alternatives`, E))
|
|
||||||
|
|
||||||
proc toPreserveHook*(`alts`: Alts; E: typedesc): Preserve[E] =
|
|
||||||
initRecord[E](symbol[E]("or"), toPreserve(`alts`.`alternatives`, E))
|
|
||||||
|
|
||||||
proc toPreserveHook*(v: WireRef; E: typedesc): Preserve[E] =
|
|
||||||
case v.kind
|
|
||||||
of WireRefKind.`mine`:
|
|
||||||
Preserve[E](kind: pkSequence, sequence: @[
|
|
||||||
Preserve[E](kind: pkSignedInteger, int: 0'i64),
|
|
||||||
toPreserve(v.`mine`.`oid`, E)])
|
|
||||||
of WireRefKind.`yours`:
|
|
||||||
Preserve[E](kind: pkSequence, sequence: @[
|
|
||||||
Preserve[E](kind: pkSignedInteger, int: 1'i64),
|
|
||||||
toPreserve(v.`yours`.`oid`, E)] &
|
|
||||||
toPreserve(v.`yours`.`attenuation`, E).sequence)
|
|
||||||
|
|
||||||
proc fromPreserveHook*[E](v: var WireRef; pr: Preserve[E]): bool =
|
|
||||||
if isSequence(pr) and len(pr) == 2 and
|
|
||||||
(pr[0].kind == pkSignedInteger and pr[0].int == 0'i64):
|
|
||||||
v = WireRef(kind: WireRefKind.`mine`)
|
|
||||||
result = fromPreserve(v.`mine`, pr)
|
|
||||||
elif isSequence(pr) and len(pr) >= 2 and
|
|
||||||
(pr[0].kind == pkSignedInteger and pr[0].int == 1'i64):
|
|
||||||
v = WireRef(kind: WireRefKind.`yours`)
|
|
||||||
result = fromPreserve(v.`yours`, pr)
|
|
||||||
|
|
||||||
proc toPreserveHook*(v: ConstructorSpec; E: typedesc): Preserve[E] =
|
|
||||||
case v.kind
|
|
||||||
of ConstructorSpecKind.`Crec`:
|
|
||||||
toPreserve(v.`crec`, E)
|
|
||||||
of ConstructorSpecKind.`Carr`:
|
|
||||||
toPreserve(v.`carr`, E)
|
|
||||||
of ConstructorSpecKind.`Cdict`:
|
|
||||||
toPreserve(v.`cdict`, E)
|
|
||||||
|
|
||||||
proc fromPreserveHook*[E](v: var ConstructorSpec; pr: Preserve[E]): bool =
|
|
||||||
if isRecord(pr) and pr.label.isSymbol("CRec"):
|
|
||||||
v = ConstructorSpec(kind: ConstructorSpecKind.`Crec`)
|
|
||||||
result = fromPreserve(v.`crec`, pr)
|
|
||||||
elif isRecord(pr) and pr.label.isSymbol("CArr"):
|
|
||||||
v = ConstructorSpec(kind: ConstructorSpecKind.`Carr`)
|
|
||||||
result = fromPreserve(v.`carr`, pr)
|
|
||||||
elif isRecord(pr) and pr.label.isSymbol("CDict"):
|
|
||||||
v = ConstructorSpec(kind: ConstructorSpecKind.`Cdict`)
|
|
||||||
result = fromPreserve(v.`cdict`, pr)
|
|
||||||
|
|
||||||
proc `cRec`*[E = void](`label`: Preserve[E]; `arity`: BiggestInt | Preserve[E]): Preserve[
|
|
||||||
E] =
|
|
||||||
## Preserves constructor for ``CRec``.
|
|
||||||
initRecord[E](symbol[E]("rec"), toPreserve(`label`, E), toPreserve(`arity`, E))
|
|
||||||
|
|
||||||
proc toPreserveHook*(`crec`: CRec; E: typedesc): Preserve[E] =
|
|
||||||
initRecord[E](symbol[E]("rec"), toPreserve(`crec`.`label`, E),
|
|
||||||
toPreserve(`crec`.`arity`, E))
|
|
||||||
|
|
||||||
proc `cArr`*[E = void](`arity`: BiggestInt | Preserve[E]): Preserve[E] =
|
|
||||||
## Preserves constructor for ``CArr``.
|
|
||||||
initRecord[E](symbol[E]("arr"), toPreserve(`arity`, E))
|
|
||||||
|
|
||||||
proc toPreserveHook*(`carr`: CArr; E: typedesc): Preserve[E] =
|
|
||||||
initRecord[E](symbol[E]("arr"), toPreserve(`carr`.`arity`, E))
|
|
||||||
|
|
||||||
proc `cDict`*[E = void](): Preserve[E] =
|
|
||||||
## Preserves constructor for ``CDict``.
|
|
||||||
initRecord[E](symbol[E]("dict"))
|
|
||||||
|
|
||||||
proc toPreserveHook*(`cdict`: CDict; E: typedesc): Preserve[E] =
|
|
||||||
initRecord[E](symbol[E]("dict"))
|
|
||||||
|
|
||||||
proc `lit`*[E = void](`value`: Preserve[E]): Preserve[E] =
|
|
||||||
## Preserves constructor for ``Lit``.
|
|
||||||
initRecord[E](symbol[E]("lit"), toPreserve(`value`, E))
|
|
||||||
|
|
||||||
proc toPreserveHook*(`lit`: Lit; E: typedesc): Preserve[E] =
|
|
||||||
initRecord[E](symbol[E]("lit"), toPreserve(`lit`.`value`, E))
|
|
||||||
|
|
||||||
proc toPreserveHook*(v: Pattern; E: typedesc): Preserve[E] =
|
|
||||||
case v.kind
|
|
||||||
of PatternKind.`Pdiscard`:
|
|
||||||
toPreserve(v.`pdiscard`, E)
|
|
||||||
of PatternKind.`Patom`:
|
|
||||||
toPreserve(v.`patom`, E)
|
|
||||||
of PatternKind.`Pembedded`:
|
|
||||||
Preserve[E](kind: pkSymbol, symbol: "Embedded")
|
|
||||||
of PatternKind.`Pbind`:
|
|
||||||
toPreserve(v.`pbind`, E)
|
|
||||||
of PatternKind.`Pand`:
|
|
||||||
toPreserve(v.`pand`, E)
|
|
||||||
of PatternKind.`Pnot`:
|
|
||||||
toPreserve(v.`pnot`, E)
|
|
||||||
of PatternKind.`Lit`:
|
|
||||||
toPreserve(v.`lit`, E)
|
|
||||||
of PatternKind.`Pcompound`:
|
|
||||||
toPreserve(v.`pcompound`, E)
|
|
||||||
|
|
||||||
proc fromPreserveHook*[E](v: var Pattern; pr: Preserve[E]): bool =
|
|
||||||
if isRecord(pr) and pr.label.isSymbol("PDiscard"):
|
|
||||||
v = Pattern(kind: PatternKind.`Pdiscard`)
|
|
||||||
result = fromPreserve(v.`pdiscard`, pr)
|
|
||||||
elif false: ## snkOr - / =<<lit>Boolean> / =<<lit>Float> / =<<lit>Double> / =<<lit>SignedInteger> / =<<lit>String> / =<<lit>ByteString> / =<<lit>Symbol>
|
|
||||||
discard
|
|
||||||
elif pr.kind == pkSymbol and pr.symbol == "Embedded":
|
|
||||||
v = Pattern(kind: PatternKind.`Pembedded`)
|
|
||||||
result = true
|
|
||||||
elif isRecord(pr) and pr.label.isSymbol("PBind"):
|
|
||||||
v = Pattern(kind: PatternKind.`Pbind`)
|
|
||||||
result = fromPreserve(v.`pbind`, pr)
|
|
||||||
elif isRecord(pr) and pr.label.isSymbol("PAnd"):
|
|
||||||
v = Pattern(kind: PatternKind.`Pand`)
|
|
||||||
result = fromPreserve(v.`pand`, pr)
|
|
||||||
elif isRecord(pr) and pr.label.isSymbol("PNot"):
|
|
||||||
v = Pattern(kind: PatternKind.`Pnot`)
|
|
||||||
result = fromPreserve(v.`pnot`, pr)
|
|
||||||
elif isRecord(pr) and pr.label.isSymbol("Lit"):
|
|
||||||
v = Pattern(kind: PatternKind.`Lit`)
|
|
||||||
result = fromPreserve(v.`lit`, pr)
|
|
||||||
elif isRecord(pr) and pr.label.isSymbol("PCompound"):
|
|
||||||
v = Pattern(kind: PatternKind.`Pcompound`)
|
|
||||||
result = fromPreserve(v.`pcompound`, pr)
|
|
||||||
|
|
||||||
proc `pDiscard`*[E = void](): Preserve[E] =
|
|
||||||
## Preserves constructor for ``PDiscard``.
|
|
||||||
initRecord[E](symbol[E]("_"))
|
|
||||||
|
|
||||||
proc toPreserveHook*(`pdiscard`: PDiscard; E: typedesc): Preserve[E] =
|
|
||||||
initRecord[E](symbol[E]("_"))
|
|
||||||
|
|
||||||
proc toPreserveHook*(v: PAtom; E: typedesc): Preserve[E] =
|
|
||||||
case v
|
|
||||||
of PAtom.`Boolean`:
|
|
||||||
symbol[E]("Boolean")
|
|
||||||
of PAtom.`Float`:
|
|
||||||
symbol[E]("Float")
|
|
||||||
of PAtom.`Double`:
|
|
||||||
symbol[E]("Double")
|
|
||||||
of PAtom.`Signedinteger`:
|
|
||||||
symbol[E]("SignedInteger")
|
|
||||||
of PAtom.`String`:
|
|
||||||
symbol[E]("String")
|
|
||||||
of PAtom.`Bytestring`:
|
|
||||||
symbol[E]("ByteString")
|
|
||||||
of PAtom.`Symbol`:
|
|
||||||
symbol[E]("Symbol")
|
|
||||||
|
|
||||||
proc fromPreserveHook*[E](v: var PAtom; pr: Preserve[E]): bool =
|
|
||||||
if isSymbol(pr):
|
|
||||||
case pr.symbol
|
|
||||||
of "Boolean":
|
|
||||||
v = PAtom.`Boolean`
|
|
||||||
result = true
|
|
||||||
of "Float":
|
|
||||||
v = PAtom.`Float`
|
|
||||||
result = true
|
|
||||||
of "Double":
|
|
||||||
v = PAtom.`Double`
|
|
||||||
result = true
|
|
||||||
of "SignedInteger":
|
|
||||||
v = PAtom.`Signedinteger`
|
|
||||||
result = true
|
|
||||||
of "String":
|
|
||||||
v = PAtom.`String`
|
|
||||||
result = true
|
|
||||||
of "ByteString":
|
|
||||||
v = PAtom.`Bytestring`
|
|
||||||
result = true
|
|
||||||
of "Symbol":
|
|
||||||
v = PAtom.`Symbol`
|
|
||||||
result = true
|
|
||||||
|
|
||||||
proc pEmbedded*[E = void](): Preserve[E] =
|
|
||||||
## ``<<lit>Embedded>``
|
|
||||||
symbol[E]("Embedded")
|
|
||||||
|
|
||||||
proc `pBind`*[E = void](`pattern`: Pattern | Preserve[E]): Preserve[E] =
|
|
||||||
## Preserves constructor for ``PBind``.
|
|
||||||
initRecord[E](symbol[E]("bind"), toPreserve(`pattern`, E))
|
|
||||||
|
|
||||||
proc toPreserveHook*(`pbind`: PBind; E: typedesc): Preserve[E] =
|
|
||||||
initRecord[E](symbol[E]("bind"), toPreserve(`pbind`.`pattern`, E))
|
|
||||||
|
|
||||||
proc `pAnd`*[E = void](`patterns`: Preserve[E]): Preserve[E] =
|
|
||||||
## Preserves constructor for ``PAnd``.
|
|
||||||
initRecord[E](symbol[E]("and"), toPreserve(`patterns`, E))
|
|
||||||
|
|
||||||
proc toPreserveHook*(`pand`: PAnd; E: typedesc): Preserve[E] =
|
|
||||||
initRecord[E](symbol[E]("and"), toPreserve(`pand`.`patterns`, E))
|
|
||||||
|
|
||||||
proc `pNot`*[E = void](`pattern`: Pattern | Preserve[E]): Preserve[E] =
|
|
||||||
## Preserves constructor for ``PNot``.
|
|
||||||
initRecord[E](symbol[E]("not"), toPreserve(`pattern`, E))
|
|
||||||
|
|
||||||
proc toPreserveHook*(`pnot`: PNot; E: typedesc): Preserve[E] =
|
|
||||||
initRecord[E](symbol[E]("not"), toPreserve(`pnot`.`pattern`, E))
|
|
||||||
|
|
||||||
proc `pCompound`*[E = void](`ctor`: ConstructorSpec | Preserve[E];
|
|
||||||
`members`: PCompoundMembers | Preserve[E]): Preserve[
|
|
||||||
E] =
|
|
||||||
## Preserves constructor for ``PCompound``.
|
|
||||||
initRecord[E](symbol[E]("compound"), toPreserve(`ctor`, E),
|
|
||||||
toPreserve(`members`, E))
|
|
||||||
|
|
||||||
proc toPreserveHook*(`pcompound`: PCompound; E: typedesc): Preserve[E] =
|
|
||||||
initRecord[E](symbol[E]("compound"), toPreserve(`pcompound`.`ctor`, E),
|
|
||||||
toPreserve(`pcompound`.`members`, E))
|
|
||||||
|
|
||||||
proc toPreserveHook*(v: Template; E: typedesc): Preserve[E] =
|
|
||||||
case v.kind
|
|
||||||
of TemplateKind.`Tattenuate`:
|
|
||||||
toPreserve(v.`tattenuate`, E)
|
|
||||||
of TemplateKind.`Tref`:
|
|
||||||
toPreserve(v.`tref`, E)
|
|
||||||
of TemplateKind.`Lit`:
|
|
||||||
toPreserve(v.`lit`, E)
|
|
||||||
of TemplateKind.`Tcompound`:
|
|
||||||
toPreserve(v.`tcompound`, E)
|
|
||||||
|
|
||||||
proc fromPreserveHook*[E](v: var Template; pr: Preserve[E]): bool =
|
|
||||||
if isRecord(pr) and pr.label.isSymbol("TAttenuate"):
|
|
||||||
v = Template(kind: TemplateKind.`Tattenuate`)
|
|
||||||
result = fromPreserve(v.`tattenuate`, pr)
|
|
||||||
elif isRecord(pr) and pr.label.isSymbol("TRef"):
|
|
||||||
v = Template(kind: TemplateKind.`Tref`)
|
|
||||||
result = fromPreserve(v.`tref`, pr)
|
|
||||||
elif isRecord(pr) and pr.label.isSymbol("Lit"):
|
|
||||||
v = Template(kind: TemplateKind.`Lit`)
|
|
||||||
result = fromPreserve(v.`lit`, pr)
|
|
||||||
elif isRecord(pr) and pr.label.isSymbol("TCompound"):
|
|
||||||
v = Template(kind: TemplateKind.`Tcompound`)
|
|
||||||
result = fromPreserve(v.`tcompound`, pr)
|
|
||||||
|
|
||||||
proc `tAttenuate`*[E = void](`template`: Template | Preserve[E];
|
|
||||||
`attenuation`: Attenuation | Preserve[E]): Preserve[
|
|
||||||
E] =
|
|
||||||
## Preserves constructor for ``TAttenuate``.
|
|
||||||
initRecord[E](symbol[E]("attenuate"), toPreserve(`template`, E),
|
|
||||||
toPreserve(`attenuation`, E))
|
|
||||||
|
|
||||||
proc toPreserveHook*(`tattenuate`: TAttenuate; E: typedesc): Preserve[E] =
|
|
||||||
initRecord[E](symbol[E]("attenuate"), toPreserve(`tattenuate`.`template`, E),
|
|
||||||
toPreserve(`tattenuate`.`attenuation`, E))
|
|
||||||
|
|
||||||
proc `tRef`*[E = void](`binding`: BiggestInt | Preserve[E]): Preserve[E] =
|
|
||||||
## Preserves constructor for ``TRef``.
|
|
||||||
initRecord[E](symbol[E]("ref"), toPreserve(`binding`, E))
|
|
||||||
|
|
||||||
proc toPreserveHook*(`tref`: TRef; E: typedesc): Preserve[E] =
|
|
||||||
initRecord[E](symbol[E]("ref"), toPreserve(`tref`.`binding`, E))
|
|
||||||
|
|
||||||
proc `tCompound`*[E = void](`ctor`: ConstructorSpec | Preserve[E];
|
|
||||||
`members`: TCompoundMembers | Preserve[E]): Preserve[
|
|
||||||
E] =
|
|
||||||
## Preserves constructor for ``TCompound``.
|
|
||||||
initRecord[E](symbol[E]("compound"), toPreserve(`ctor`, E),
|
|
||||||
toPreserve(`members`, E))
|
|
||||||
|
|
||||||
proc toPreserveHook*(`tcompound`: TCompound; E: typedesc): Preserve[E] =
|
|
||||||
initRecord[E](symbol[E]("compound"), toPreserve(`tcompound`.`ctor`, E),
|
|
||||||
toPreserve(`tcompound`.`members`, E))
|
|
||||||
|
|
||||||
proc `$`*[E](x: SturdyRef[E] | Attenuation[E] | Caveat[E] | Rewrite[E] | Alts[E] |
|
|
||||||
Oid |
|
|
||||||
WireRef[E] |
|
|
||||||
ConstructorSpec[E] |
|
|
||||||
CRec[E] |
|
|
||||||
CArr |
|
|
||||||
CDict |
|
|
||||||
Lit[E] |
|
|
||||||
Pattern[E] |
|
|
||||||
PDiscard |
|
|
||||||
PAtom |
|
|
||||||
PBind[E] |
|
PBind[E] |
|
||||||
PAnd[E] |
|
Lit[E] |
|
||||||
PNot[E] |
|
|
||||||
PCompound[E] |
|
|
||||||
PCompoundMembers[E] |
|
|
||||||
Template[E] |
|
|
||||||
TAttenuate[E] |
|
|
||||||
TRef |
|
|
||||||
TCompound[E] |
|
TCompound[E] |
|
||||||
TCompoundMembers[E]): string =
|
Attenuation[E] |
|
||||||
|
Template[E] |
|
||||||
|
Caveat[E] |
|
||||||
|
PCompoundMembers[E] |
|
||||||
|
PNot[E] |
|
||||||
|
SturdyRef[E] |
|
||||||
|
WireRef[E] |
|
||||||
|
TAttenuate[E] |
|
||||||
|
Alts[E] |
|
||||||
|
Pattern[E]): string =
|
||||||
`$`(toPreserve(x, E))
|
`$`(toPreserve(x, E))
|
||||||
|
|
||||||
proc `encode`*[E](x: SturdyRef[E] | Attenuation[E] | Caveat[E] | Rewrite[E] |
|
proc encode*[E](x: CRec[E] | PCompound[E] | ConstructorSpec[E] | PAnd[E] |
|
||||||
Alts[E] |
|
Rewrite[E] |
|
||||||
Oid |
|
TCompoundMembers[E] |
|
||||||
WireRef[E] |
|
|
||||||
ConstructorSpec[E] |
|
|
||||||
CRec[E] |
|
|
||||||
CArr |
|
|
||||||
CDict |
|
|
||||||
Lit[E] |
|
|
||||||
Pattern[E] |
|
|
||||||
PDiscard |
|
|
||||||
PAtom |
|
|
||||||
PBind[E] |
|
PBind[E] |
|
||||||
PAnd[E] |
|
Lit[E] |
|
||||||
PNot[E] |
|
|
||||||
PCompound[E] |
|
|
||||||
PCompoundMembers[E] |
|
|
||||||
Template[E] |
|
|
||||||
TAttenuate[E] |
|
|
||||||
TRef |
|
|
||||||
TCompound[E] |
|
TCompound[E] |
|
||||||
TCompoundMembers[E]): seq[byte] =
|
Attenuation[E] |
|
||||||
|
Template[E] |
|
||||||
|
Caveat[E] |
|
||||||
|
PCompoundMembers[E] |
|
||||||
|
PNot[E] |
|
||||||
|
SturdyRef[E] |
|
||||||
|
WireRef[E] |
|
||||||
|
TAttenuate[E] |
|
||||||
|
Alts[E] |
|
||||||
|
Pattern[E]): seq[byte] =
|
||||||
encode(toPreserve(x, E))
|
encode(toPreserve(x, E))
|
||||||
|
|
||||||
|
proc `$`*(x: TRef | PDiscard | CArr | Oid | CDict): string =
|
||||||
|
`$`(toPreserve(x))
|
||||||
|
|
||||||
|
proc encode*(x: TRef | PDiscard | CArr | Oid | CDict): seq[byte] =
|
||||||
|
encode(toPreserve(x))
|
||||||
|
|
|
@ -3,53 +3,27 @@ import
|
||||||
std/typetraits, preserves
|
std/typetraits, preserves
|
||||||
|
|
||||||
type
|
type
|
||||||
TcpRemote* {.record: "tcp-remote".} = ref object ## ``<tcp-remote @host string @port int>``
|
TcpLocal* {.preservesRecord: "tcp-local".} = object
|
||||||
`host`*: string
|
`host`*: string
|
||||||
`port`*: BiggestInt
|
`port`*: BiggestInt
|
||||||
|
|
||||||
TcpLocal* {.record: "tcp-local".} = ref object ## ``<tcp-local @host string @port int>``
|
TcpPeerInfo*[E] {.preservesRecord: "tcp-peer".} = ref object
|
||||||
`host`*: string
|
|
||||||
`port`*: BiggestInt
|
|
||||||
|
|
||||||
TcpPeerInfo*[E = void] {.record: "tcp-peer".} = ref object ## ``<tcp-peer @handle #!any @local TcpLocal @remote TcpRemote>``
|
|
||||||
`handle`*: Preserve[E]
|
`handle`*: Preserve[E]
|
||||||
`local`*: TcpLocal
|
`local`*: TcpLocal
|
||||||
`remote`*: TcpRemote
|
`remote`*: TcpRemote
|
||||||
|
|
||||||
proc `tcpRemote`*[E = void](`host`: string | Preserve[E];
|
TcpRemote* {.preservesRecord: "tcp-remote".} = object
|
||||||
`port`: BiggestInt | Preserve[E]): Preserve[E] =
|
`host`*: string
|
||||||
## Preserves constructor for ``TcpRemote``.
|
`port`*: BiggestInt
|
||||||
initRecord[E](symbol[E]("tcp-remote"), toPreserve(`host`, E),
|
|
||||||
toPreserve(`port`, E))
|
|
||||||
|
|
||||||
proc toPreserveHook*(`tcpremote`: TcpRemote; E: typedesc): Preserve[E] =
|
proc `$`*[E](x: TcpPeerInfo[E]): string =
|
||||||
initRecord[E](symbol[E]("tcp-remote"), toPreserve(`tcpremote`.`host`, E),
|
|
||||||
toPreserve(`tcpremote`.`port`, E))
|
|
||||||
|
|
||||||
proc `tcpLocal`*[E = void](`host`: string | Preserve[E];
|
|
||||||
`port`: BiggestInt | Preserve[E]): Preserve[E] =
|
|
||||||
## Preserves constructor for ``TcpLocal``.
|
|
||||||
initRecord[E](symbol[E]("tcp-local"), toPreserve(`host`, E),
|
|
||||||
toPreserve(`port`, E))
|
|
||||||
|
|
||||||
proc toPreserveHook*(`tcplocal`: TcpLocal; E: typedesc): Preserve[E] =
|
|
||||||
initRecord[E](symbol[E]("tcp-local"), toPreserve(`tcplocal`.`host`, E),
|
|
||||||
toPreserve(`tcplocal`.`port`, E))
|
|
||||||
|
|
||||||
proc `tcpPeerInfo`*[E = void](`handle`: Preserve[E];
|
|
||||||
`local`: TcpLocal | Preserve[E];
|
|
||||||
`remote`: TcpRemote | Preserve[E]): Preserve[E] =
|
|
||||||
## Preserves constructor for ``TcpPeerInfo``.
|
|
||||||
initRecord[E](symbol[E]("tcp-peer"), toPreserve(`handle`, E),
|
|
||||||
toPreserve(`local`, E), toPreserve(`remote`, E))
|
|
||||||
|
|
||||||
proc toPreserveHook*(`tcppeerinfo`: TcpPeerInfo; E: typedesc): Preserve[E] =
|
|
||||||
initRecord[E](symbol[E]("tcp-peer"), toPreserve(`tcppeerinfo`.`handle`, E),
|
|
||||||
toPreserve(`tcppeerinfo`.`local`, E),
|
|
||||||
toPreserve(`tcppeerinfo`.`remote`, E))
|
|
||||||
|
|
||||||
proc `$`*[E](x: TcpRemote | TcpLocal | TcpPeerInfo[E]): string =
|
|
||||||
`$`(toPreserve(x, E))
|
`$`(toPreserve(x, E))
|
||||||
|
|
||||||
proc `encode`*[E](x: TcpRemote | TcpLocal | TcpPeerInfo[E]): seq[byte] =
|
proc encode*[E](x: TcpPeerInfo[E]): seq[byte] =
|
||||||
encode(toPreserve(x, E))
|
encode(toPreserve(x, E))
|
||||||
|
|
||||||
|
proc `$`*(x: TcpLocal | TcpRemote): string =
|
||||||
|
`$`(toPreserve(x))
|
||||||
|
|
||||||
|
proc encode*(x: TcpLocal | TcpRemote): seq[byte] =
|
||||||
|
encode(toPreserve(x))
|
||||||
|
|
|
@ -3,74 +3,28 @@ import
|
||||||
std/typetraits, preserves
|
std/typetraits, preserves
|
||||||
|
|
||||||
type
|
type
|
||||||
SetTimer*[E = void] {.record: "set-timer".} = ref object ## ``<set-timer @label any @msecs double @kind TimerKind>``
|
TimerExpired*[E] {.preservesRecord: "timer-expired".} = ref object
|
||||||
|
`label`*: Preserve[E]
|
||||||
|
`msecs`*: float64
|
||||||
|
|
||||||
|
SetTimer*[E] {.preservesRecord: "set-timer".} = ref object
|
||||||
`label`*: Preserve[E]
|
`label`*: Preserve[E]
|
||||||
`msecs`*: float64
|
`msecs`*: float64
|
||||||
`kind`*: TimerKind
|
`kind`*: TimerKind
|
||||||
|
|
||||||
TimerExpired*[E = void] {.record: "timer-expired".} = ref object ## ``<timer-expired @label any @msecs double>``
|
`TimerKind`* {.preservesOr.} = enum
|
||||||
`label`*: Preserve[E]
|
|
||||||
`msecs`*: float64
|
|
||||||
|
|
||||||
TimerKind* {.pure.} = enum ## ``/ =<<lit>relative> / =<<lit>absolute> / =<<lit>clear>``
|
|
||||||
`relative`, `absolute`, `clear`
|
`relative`, `absolute`, `clear`
|
||||||
LaterThan* {.record: "later-than".} = ref object ## ``<later-than @msecs double>``
|
LaterThan* {.preservesRecord: "later-than".} = object
|
||||||
`msecs`*: float64
|
`msecs`*: float64
|
||||||
|
|
||||||
proc `setTimer`*[E = void](`label`: Preserve[E]; `msecs`: float64 | Preserve[E];
|
proc `$`*[E](x: TimerExpired[E] | SetTimer[E]): string =
|
||||||
`kind`: TimerKind | Preserve[E]): Preserve[E] =
|
|
||||||
## Preserves constructor for ``SetTimer``.
|
|
||||||
initRecord[E](symbol[E]("set-timer"), toPreserve(`label`, E),
|
|
||||||
toPreserve(`msecs`, E), toPreserve(`kind`, E))
|
|
||||||
|
|
||||||
proc toPreserveHook*(`settimer`: SetTimer; E: typedesc): Preserve[E] =
|
|
||||||
initRecord[E](symbol[E]("set-timer"), toPreserve(`settimer`.`label`, E),
|
|
||||||
toPreserve(`settimer`.`msecs`, E),
|
|
||||||
toPreserve(`settimer`.`kind`, E))
|
|
||||||
|
|
||||||
proc `timerExpired`*[E = void](`label`: Preserve[E];
|
|
||||||
`msecs`: float64 | Preserve[E]): Preserve[E] =
|
|
||||||
## Preserves constructor for ``TimerExpired``.
|
|
||||||
initRecord[E](symbol[E]("timer-expired"), toPreserve(`label`, E),
|
|
||||||
toPreserve(`msecs`, E))
|
|
||||||
|
|
||||||
proc toPreserveHook*(`timerexpired`: TimerExpired; E: typedesc): Preserve[E] =
|
|
||||||
initRecord[E](symbol[E]("timer-expired"),
|
|
||||||
toPreserve(`timerexpired`.`label`, E),
|
|
||||||
toPreserve(`timerexpired`.`msecs`, E))
|
|
||||||
|
|
||||||
proc toPreserveHook*(v: TimerKind; E: typedesc): Preserve[E] =
|
|
||||||
case v
|
|
||||||
of TimerKind.`relative`:
|
|
||||||
symbol[E]("relative")
|
|
||||||
of TimerKind.`absolute`:
|
|
||||||
symbol[E]("absolute")
|
|
||||||
of TimerKind.`clear`:
|
|
||||||
symbol[E]("clear")
|
|
||||||
|
|
||||||
proc fromPreserveHook*[E](v: var TimerKind; pr: Preserve[E]): bool =
|
|
||||||
if isSymbol(pr):
|
|
||||||
case pr.symbol
|
|
||||||
of "relative":
|
|
||||||
v = TimerKind.`relative`
|
|
||||||
result = true
|
|
||||||
of "absolute":
|
|
||||||
v = TimerKind.`absolute`
|
|
||||||
result = true
|
|
||||||
of "clear":
|
|
||||||
v = TimerKind.`clear`
|
|
||||||
result = true
|
|
||||||
|
|
||||||
proc `laterThan`*[E = void](`msecs`: float64 | Preserve[E]): Preserve[E] =
|
|
||||||
## Preserves constructor for ``LaterThan``.
|
|
||||||
initRecord[E](symbol[E]("later-than"), toPreserve(`msecs`, E))
|
|
||||||
|
|
||||||
proc toPreserveHook*(`laterthan`: LaterThan; E: typedesc): Preserve[E] =
|
|
||||||
initRecord[E](symbol[E]("later-than"), toPreserve(`laterthan`.`msecs`, E))
|
|
||||||
|
|
||||||
proc `$`*[E](x: SetTimer[E] | TimerExpired[E] | TimerKind | LaterThan): string =
|
|
||||||
`$`(toPreserve(x, E))
|
`$`(toPreserve(x, E))
|
||||||
|
|
||||||
proc `encode`*[E](x: SetTimer[E] | TimerExpired[E] | TimerKind | LaterThan): seq[
|
proc encode*[E](x: TimerExpired[E] | SetTimer[E]): seq[byte] =
|
||||||
byte] =
|
|
||||||
encode(toPreserve(x, E))
|
encode(toPreserve(x, E))
|
||||||
|
|
||||||
|
proc `$`*(x: LaterThan): string =
|
||||||
|
`$`(toPreserve(x))
|
||||||
|
|
||||||
|
proc encode*(x: LaterThan): seq[byte] =
|
||||||
|
encode(toPreserve(x))
|
||||||
|
|
|
@ -3,51 +3,20 @@ import
|
||||||
std/typetraits, preserves
|
std/typetraits, preserves
|
||||||
|
|
||||||
type
|
type
|
||||||
Tcp* {.record: "tcp".} = ref object ## ``<tcp @host string @port int>``
|
WebSocket* {.preservesRecord: "ws".} = object
|
||||||
|
`url`*: string
|
||||||
|
|
||||||
|
Stdio* {.preservesRecord: "stdio".} = object
|
||||||
|
|
||||||
|
Unix* {.preservesRecord: "unix".} = object
|
||||||
|
`path`*: string
|
||||||
|
|
||||||
|
Tcp* {.preservesRecord: "tcp".} = object
|
||||||
`host`*: string
|
`host`*: string
|
||||||
`port`*: BiggestInt
|
`port`*: BiggestInt
|
||||||
|
|
||||||
Unix* {.record: "unix".} = ref object ## ``<unix @path string>``
|
proc `$`*(x: WebSocket | Stdio | Unix | Tcp): string =
|
||||||
`path`*: string
|
`$`(toPreserve(x))
|
||||||
|
|
||||||
WebSocket* {.record: "ws".} = ref object ## ``<ws @url string>``
|
proc encode*(x: WebSocket | Stdio | Unix | Tcp): seq[byte] =
|
||||||
`url`*: string
|
encode(toPreserve(x))
|
||||||
|
|
||||||
Stdio* {.record: "stdio".} = object ## ``<stdio>``
|
|
||||||
discard
|
|
||||||
|
|
||||||
proc `tcp`*[E = void](`host`: string | Preserve[E];
|
|
||||||
`port`: BiggestInt | Preserve[E]): Preserve[E] =
|
|
||||||
## Preserves constructor for ``Tcp``.
|
|
||||||
initRecord[E](symbol[E]("tcp"), toPreserve(`host`, E), toPreserve(`port`, E))
|
|
||||||
|
|
||||||
proc toPreserveHook*(`tcp`: Tcp; E: typedesc): Preserve[E] =
|
|
||||||
initRecord[E](symbol[E]("tcp"), toPreserve(`tcp`.`host`, E),
|
|
||||||
toPreserve(`tcp`.`port`, E))
|
|
||||||
|
|
||||||
proc `unix`*[E = void](`path`: string | Preserve[E]): Preserve[E] =
|
|
||||||
## Preserves constructor for ``Unix``.
|
|
||||||
initRecord[E](symbol[E]("unix"), toPreserve(`path`, E))
|
|
||||||
|
|
||||||
proc toPreserveHook*(`unix`: Unix; E: typedesc): Preserve[E] =
|
|
||||||
initRecord[E](symbol[E]("unix"), toPreserve(`unix`.`path`, E))
|
|
||||||
|
|
||||||
proc `webSocket`*[E = void](`url`: string | Preserve[E]): Preserve[E] =
|
|
||||||
## Preserves constructor for ``WebSocket``.
|
|
||||||
initRecord[E](symbol[E]("ws"), toPreserve(`url`, E))
|
|
||||||
|
|
||||||
proc toPreserveHook*(`websocket`: WebSocket; E: typedesc): Preserve[E] =
|
|
||||||
initRecord[E](symbol[E]("ws"), toPreserve(`websocket`.`url`, E))
|
|
||||||
|
|
||||||
proc `stdio`*[E = void](): Preserve[E] =
|
|
||||||
## Preserves constructor for ``Stdio``.
|
|
||||||
initRecord[E](symbol[E]("stdio"))
|
|
||||||
|
|
||||||
proc toPreserveHook*(`stdio`: Stdio; E: typedesc): Preserve[E] =
|
|
||||||
initRecord[E](symbol[E]("stdio"))
|
|
||||||
|
|
||||||
proc `$`*[E](x: Tcp | Unix | WebSocket | Stdio): string =
|
|
||||||
`$`(toPreserve(x, E))
|
|
||||||
|
|
||||||
proc `encode`*[E](x: Tcp | Unix | WebSocket | Stdio): seq[byte] =
|
|
||||||
encode(toPreserve(x, E))
|
|
||||||
|
|
|
@ -3,22 +3,12 @@ import
|
||||||
std/typetraits, preserves
|
std/typetraits, preserves
|
||||||
|
|
||||||
type
|
type
|
||||||
Instance*[E = void] {.record: "Instance".} = ref object ## ``<Instance @name string @argument any>``
|
Instance*[E] {.preservesRecord: "Instance".} = ref object
|
||||||
`name`*: string
|
`name`*: string
|
||||||
`argument`*: Preserve[E]
|
`argument`*: Preserve[E]
|
||||||
|
|
||||||
proc `instance`*[E = void](`name`: string | Preserve[E]; `argument`: Preserve[E]): Preserve[
|
|
||||||
E] =
|
|
||||||
## Preserves constructor for ``Instance``.
|
|
||||||
initRecord[E](symbol[E]("Instance"), toPreserve(`name`, E),
|
|
||||||
toPreserve(`argument`, E))
|
|
||||||
|
|
||||||
proc toPreserveHook*(`instance`: Instance; E: typedesc): Preserve[E] =
|
|
||||||
initRecord[E](symbol[E]("Instance"), toPreserve(`instance`.`name`, E),
|
|
||||||
toPreserve(`instance`.`argument`, E))
|
|
||||||
|
|
||||||
proc `$`*[E](x: Instance[E]): string =
|
proc `$`*[E](x: Instance[E]): string =
|
||||||
`$`(toPreserve(x, E))
|
`$`(toPreserve(x, E))
|
||||||
|
|
||||||
proc `encode`*[E](x: Instance[E]): seq[byte] =
|
proc encode*[E](x: Instance[E]): seq[byte] =
|
||||||
encode(toPreserve(x, E))
|
encode(toPreserve(x, E))
|
||||||
|
|
|
@ -0,0 +1,390 @@
|
||||||
|
# SPDX-FileCopyrightText: ☭ 2021 Emery Hemingway
|
||||||
|
# SPDX-License-Identifier: Unlicense
|
||||||
|
|
||||||
|
import std/[asyncdispatch, options, tables]
|
||||||
|
import preserves, preserves/parse
|
||||||
|
import ../syndicate/protocols/[protocol, sturdy]
|
||||||
|
import ./actors, ./dataspaces
|
||||||
|
|
||||||
|
type Oid = sturdy.Oid
|
||||||
|
|
||||||
|
type
|
||||||
|
Assertion = Preserve[Ref]
|
||||||
|
WireAssertion = Preserve[WireRef]
|
||||||
|
WireRef = sturdy.WireRef[Ref]
|
||||||
|
Packet = protocol.Packet[WireRef]
|
||||||
|
|
||||||
|
Turn = actors.Turn
|
||||||
|
|
||||||
|
WireSymbol = ref object
|
||||||
|
oid: Oid
|
||||||
|
`ref`: Ref
|
||||||
|
membrane: Membrane
|
||||||
|
count: int
|
||||||
|
|
||||||
|
Membrane = object
|
||||||
|
byOid: Table[Oid, WireSymbol]
|
||||||
|
byRef: Table[Ref, WireSymbol]
|
||||||
|
|
||||||
|
#[
|
||||||
|
proc `$`(ws: WireSymbol): string =
|
||||||
|
"<ws:" & $ws.oid & "/" & $ws.count & "/" & $ws.`ref` &>"
|
||||||
|
]#
|
||||||
|
|
||||||
|
proc grab(mb: var Membrane; key: Oid|Ref; transient: bool; alloc: proc(): WireSymbol {.gcsafe.}): WireSymbol {.deprecated: "not idomatic Nim".} =
|
||||||
|
when key is Oid:
|
||||||
|
result = mb.byOid.getOrDefault(key)
|
||||||
|
elif key is ref:
|
||||||
|
result = mb.byRef.getOrDefault(key)
|
||||||
|
if result.isNil:
|
||||||
|
result = alloc()
|
||||||
|
mb.byOid[result.oid] = result
|
||||||
|
mb.byRef[result.`ref`] = result
|
||||||
|
if not transient: inc result.count
|
||||||
|
|
||||||
|
proc drop(mb: var Membrane; ws: WireSymbol) =
|
||||||
|
dec ws.count
|
||||||
|
if ws.count < 1:
|
||||||
|
mb.byOid.del ws.oid
|
||||||
|
mb.byRef.del ws.`ref`
|
||||||
|
|
||||||
|
type
|
||||||
|
PacketWriter = proc (bs: seq[byte]): Future[void] {.gcsafe.}
|
||||||
|
RelaySetup = proc (turn: var Turn; relay: Relay) {.gcsafe.}
|
||||||
|
|
||||||
|
Relay = ref object of RootObj
|
||||||
|
facet: Facet
|
||||||
|
inboundAssertions: Table[Handle,
|
||||||
|
tuple[localHandle: Handle, imported: seq[WireSymbol]]]
|
||||||
|
outboundAssertions: Table[Handle, seq[WireSymbol]]
|
||||||
|
exported: Membrane
|
||||||
|
imported: Membrane
|
||||||
|
nextLocalOid: Oid
|
||||||
|
pendingTurn: protocol.Turn[WireRef]
|
||||||
|
packetWriter: PacketWriter
|
||||||
|
untrusted: bool
|
||||||
|
|
||||||
|
SyncPeerEntity = ref object of Entity
|
||||||
|
relay: Relay
|
||||||
|
peer: Ref
|
||||||
|
handleMap: Table[Handle, Handle]
|
||||||
|
e: WireSymbol
|
||||||
|
|
||||||
|
RelayEntity = ref object of Entity
|
||||||
|
label: string
|
||||||
|
relay: Relay
|
||||||
|
|
||||||
|
#[
|
||||||
|
proc newSyncPeerEntity(r: Relay; p: Ref): SyncPeerEntity =
|
||||||
|
SyncPeerEntity(relay: r, peer: p)
|
||||||
|
]#
|
||||||
|
|
||||||
|
proc releaseRefOut(r: Relay; e: WireSymbol) =
|
||||||
|
r.exported.drop e
|
||||||
|
|
||||||
|
method publish(se: SyncPeerEntity; t: var Turn; v: Assertion; h: Handle) =
|
||||||
|
se.handleMap[h] = publish(t, se.peer, v)
|
||||||
|
|
||||||
|
method retract(se: SyncPeerEntity; t: var Turn; h: Handle) =
|
||||||
|
var other: Handle
|
||||||
|
if se.handleMap.pop(h, other):
|
||||||
|
retract(t, other)
|
||||||
|
|
||||||
|
method message(se: SyncPeerEntity; t: var Turn; v: Assertion) =
|
||||||
|
if not se.e.isNil:
|
||||||
|
se.relay.releaseRefOut(se.e)
|
||||||
|
message(t, se.peer, v)
|
||||||
|
|
||||||
|
method sync(se: SyncPeerEntity; t: var Turn; peer: Ref) =
|
||||||
|
sync(t, se.peer, peer)
|
||||||
|
|
||||||
|
proc newRelayEntity(label: string; r: Relay; o: Oid): RelayEntity =
|
||||||
|
RelayEntity(label: label, relay: r, oid: o)
|
||||||
|
|
||||||
|
#[
|
||||||
|
proc `$`(ws: WireSymbol): string =
|
||||||
|
"<ws:" & $ws.oid & "/" & $ws.count & "/" & $ws.`ref` &>"
|
||||||
|
]#
|
||||||
|
|
||||||
|
proc `$`(re: RelayEntity): string =
|
||||||
|
"<Relay:" & re.label & ":" & $re.oid & ">"
|
||||||
|
|
||||||
|
proc rewriteRefOut(relay: Relay; `ref`: Ref; transient: bool; exported: var seq[WireSymbol]): WireRef =
|
||||||
|
#[
|
||||||
|
if not relay.untrusted:
|
||||||
|
result = WireRef(
|
||||||
|
orKind: WirerefKind.yours,
|
||||||
|
yours: WireRefYours[Ref](
|
||||||
|
oid: `ref`.target.oid,
|
||||||
|
attenuation: `ref`.attenuation))
|
||||||
|
]#
|
||||||
|
let e = grab(relay.exported, `ref`, transient) do () -> WireSymbol:
|
||||||
|
assert(not transient, "Cannot send transient reference")
|
||||||
|
result = WireSymbol( oid: relay.nextLocalOid, `ref`: `ref`)
|
||||||
|
inc relay.nextLocalOid
|
||||||
|
exported.add e
|
||||||
|
WireRef(
|
||||||
|
orKind: WireRefKind.mine,
|
||||||
|
mine: WireRefMine(oid: e.oid))
|
||||||
|
|
||||||
|
proc rewriteOut(relay: Relay; v: Assertion; transient: bool):
|
||||||
|
tuple[rewritten: WireAssertion, exported: seq[WireSymbol]] =
|
||||||
|
var exported: seq[WireSymbol]
|
||||||
|
var rewritten = mapEmbeds[Ref, WireRef](v) do (r: Ref) -> WireRef:
|
||||||
|
result = rewriteRefOut(relay, r, transient, exported)
|
||||||
|
(rewritten, exported)
|
||||||
|
|
||||||
|
proc register(relay: Relay; v: Assertion; h: Handle): WireAssertion =
|
||||||
|
var (rewritten, exported) = rewriteOut(relay, v, false)
|
||||||
|
relay.outboundAssertions[h] = exported
|
||||||
|
rewritten
|
||||||
|
|
||||||
|
proc deregister(relay: Relay; h: Handle) =
|
||||||
|
var outbound: seq[WireSymbol]
|
||||||
|
if relay.outboundAssertions.pop(h, outbound):
|
||||||
|
for e in outbound: releaseRefOut(relay, e)
|
||||||
|
|
||||||
|
proc send(r: Relay; msg: seq[byte]): Future[void] =
|
||||||
|
assert(not r.packetWriter.isNil, "missing packetWriter proc")
|
||||||
|
r.packetWriter(msg)
|
||||||
|
|
||||||
|
proc send(r: Relay; rOid: protocol.Oid; m: Event[WireRef]) =
|
||||||
|
if r.pendingTurn.len == 0:
|
||||||
|
callSoon:
|
||||||
|
r.facet.run do (turn: var Turn):
|
||||||
|
var pkt = $Packet(
|
||||||
|
orKind: PacketKind.Turn,
|
||||||
|
turn: move r.pendingTurn)
|
||||||
|
echo "C: ", pkt
|
||||||
|
#asyncCheck(turn, r.send(encode pkt))
|
||||||
|
asyncCheck(turn, r.send(cast[seq[byte]](pkt)))
|
||||||
|
r.pendingTurn.add TurnEvent[WireRef](oid: rOid, event: m)
|
||||||
|
|
||||||
|
proc send(re: RelayEntity; ev: Event) =
|
||||||
|
send(re.relay, protocol.Oid re.oid, ev)
|
||||||
|
|
||||||
|
method publish(re: RelayEntity; t: var Turn; v: Assertion; h: Handle) =
|
||||||
|
var ev = protocol.Event[WireRef](
|
||||||
|
orKind: EventKind.Assert,
|
||||||
|
`assert`: protocol.Assert[WireRef](
|
||||||
|
assertion: re.relay.register(v, h),
|
||||||
|
handle: h))
|
||||||
|
re.send ev
|
||||||
|
|
||||||
|
method retract(re: RelayEntity; t: var Turn; h: Handle) =
|
||||||
|
re.relay.deregister h
|
||||||
|
re.send Event[WireRef](
|
||||||
|
orKind: EventKind.Retract,
|
||||||
|
retract: Retract(handle: h))
|
||||||
|
|
||||||
|
method message(re: RelayEntity; turn: var Turn; msg: Assertion) =
|
||||||
|
var ev = Event[WireRef](orKind: EventKind.Message)
|
||||||
|
var (body, _) = rewriteOut(re.relay, msg, true)
|
||||||
|
ev.message.body = body
|
||||||
|
re.send ev
|
||||||
|
|
||||||
|
method sync(re: RelayEntity; turn: var Turn; peer: Ref) =
|
||||||
|
var
|
||||||
|
peerEntity = SyncPeerEntity(relay: re.relay, peer: peer)
|
||||||
|
exported: seq[WireSymbol]
|
||||||
|
discard rewriteRefOut(re.relay, turn.newRef(peerEntity), false, exported)
|
||||||
|
# TODO: discard?
|
||||||
|
peerEntity.e = exported[0]
|
||||||
|
re.send Event[WireRef](
|
||||||
|
orKind: EventKind.Sync,
|
||||||
|
sync: Sync[WireRef](peer: embed toPreserve(false, WireRef))) # TODO: send the WireRef?
|
||||||
|
|
||||||
|
using
|
||||||
|
relay: Relay
|
||||||
|
facet: Facet
|
||||||
|
|
||||||
|
proc lookupLocal(relay; oid: Oid): Ref =
|
||||||
|
try: relay.exported.byOid[oid].`ref`
|
||||||
|
except KeyError: newInertRef()
|
||||||
|
|
||||||
|
proc isInert(r: Ref): bool =
|
||||||
|
r.target.isNil
|
||||||
|
|
||||||
|
proc rewriteRefIn(relay; facet; n: WireRef, imported: var seq[WireSymbol]): Ref =
|
||||||
|
case n.orKind
|
||||||
|
of WireRefKind.mine:
|
||||||
|
let e = relay.imported.grab(n.mine.oid, false) do () -> WireSymbol:
|
||||||
|
WireSymbol(
|
||||||
|
oid: n.mine.oid,
|
||||||
|
`ref`: newRef(facet, newRelayEntity("rewriteRefIn", relay, n.mine.oid)))
|
||||||
|
imported.add e
|
||||||
|
result = e.`ref`
|
||||||
|
of WireRefKind.yours:
|
||||||
|
let r = relay.lookupLocal(n.yours.oid)
|
||||||
|
if n.yours.attenuation.len == 0 or r.isInert:
|
||||||
|
result = r
|
||||||
|
else:
|
||||||
|
raiseAssert "attenuation not implemented"
|
||||||
|
|
||||||
|
proc rewriteIn(relay; facet; a: Preserve[WireRef]):
|
||||||
|
tuple[rewritten: Assertion; imported: seq[WireSymbol]] =
|
||||||
|
var
|
||||||
|
imported: seq[WireSymbol]
|
||||||
|
rewritten = mapEmbeds(a) do (wr: WireRef) -> Ref:
|
||||||
|
rewriteRefIn(relay, facet, wr, imported)
|
||||||
|
(rewritten, imported)
|
||||||
|
|
||||||
|
proc close(r: Relay) = discard
|
||||||
|
|
||||||
|
proc dispatch(relay: Relay; turn: var Turn; `ref`: Ref; event: Event[WireRef]) =
|
||||||
|
case event.orKind
|
||||||
|
of EventKind.Assert:
|
||||||
|
let (a, imported) = rewriteIn(relay, turn.activeFacet, event.assert.assertion)
|
||||||
|
relay.inboundAssertions[event.assert.handle] =
|
||||||
|
(turn.publish(`ref`, a), imported,)
|
||||||
|
|
||||||
|
of EventKind.Retract:
|
||||||
|
let remoteHandle = event.retract.handle
|
||||||
|
var outbound: tuple[localHandle: Handle, imported: seq[WireSymbol]]
|
||||||
|
if relay.inboundAssertions.pop(remoteHandle, outbound):
|
||||||
|
for e in outbound.imported: relay.imported.drop e
|
||||||
|
turn.retract(outbound.localHandle)
|
||||||
|
|
||||||
|
of EventKind.Message:
|
||||||
|
let (a, imported) = rewriteIn(relay, turn.activeFacet, event.message.body)
|
||||||
|
assert imported.len == 0, "Cannot receive transient reference"
|
||||||
|
turn.message(`ref`, a)
|
||||||
|
|
||||||
|
of EventKind.Sync:
|
||||||
|
discard # TODO
|
||||||
|
#[
|
||||||
|
var imported: seq[WireSymbol]
|
||||||
|
let k = relay.rewriteRefIn(turn, evenr.sync.peer, imported)
|
||||||
|
turn.sync(`ref`) do (turn: var Turn):
|
||||||
|
turn.message(k, true)
|
||||||
|
for e in imported: relay.imported.del e
|
||||||
|
]#
|
||||||
|
|
||||||
|
proc dispatch(relay: Relay; v: Preserve[WireRef]) =
|
||||||
|
run(relay.facet) do (t: var Turn):
|
||||||
|
var pkt: Packet
|
||||||
|
if fromPreserve(pkt, v):
|
||||||
|
case pkt.orKind
|
||||||
|
of PacketKind.Turn:
|
||||||
|
for te in pkt.turn:
|
||||||
|
dispatch(relay, t, lookupLocal(relay, te.oid.Oid), te.event)
|
||||||
|
of PacketKind.Error:
|
||||||
|
relay.facet.log("Error from server: ", pkt.error.message, " (detail: ", pkt.error.detail, ")")
|
||||||
|
close relay
|
||||||
|
|
||||||
|
|
||||||
|
proc recv(relay: Relay; buf: seq[byte]) =
|
||||||
|
# var pkt = decodePreserves(buf, WireRef)
|
||||||
|
var pkt = cast[Preserve[WireRef]](
|
||||||
|
parsePreserves(cast[string](buf), sturdy.WireRef[void]))
|
||||||
|
# the compiler cannot convert `Preserve[void]` to `Preserve[WireRef[Ref]]`
|
||||||
|
# so convert to `Preserve[WireRef[void]]` and cast.
|
||||||
|
echo "S: ", pkt
|
||||||
|
dispatch(relay, pkt)
|
||||||
|
|
||||||
|
type
|
||||||
|
RelayOptions = object of RootObj
|
||||||
|
packetWriter: PacketWriter
|
||||||
|
setup: RelaySetup
|
||||||
|
untrusted: bool
|
||||||
|
RelayActorOptions = object of RelayOptions
|
||||||
|
initialOid: Option[Oid]
|
||||||
|
initialRef: Ref
|
||||||
|
nextLocalOid: Option[Oid]
|
||||||
|
|
||||||
|
proc newRelay(turn: var Turn; opts: RelayOptions): Relay =
|
||||||
|
result = Relay(
|
||||||
|
facet: turn.activeFacet,
|
||||||
|
packetWriter: opts.packetWriter,
|
||||||
|
untrusted: opts.untrusted)
|
||||||
|
discard result.facet.preventInertCheck()
|
||||||
|
opts.setup(turn, result)
|
||||||
|
|
||||||
|
proc spawnRelay(name: string; turn: var Turn; opts: RelayActorOptions): Future[Ref] =
|
||||||
|
var fut = newFuture[Ref]"spawnRelay"
|
||||||
|
spawn(name, turn) do (turn: var Turn):
|
||||||
|
let relay = newRelay(turn, opts)
|
||||||
|
if not opts.initialRef.isNil:
|
||||||
|
var exported: seq[WireSymbol]
|
||||||
|
discard rewriteRefOut(relay, opts.initialRef, false, exported)
|
||||||
|
if opts.initialOid.isSome:
|
||||||
|
var imported: seq[WireSymbol]
|
||||||
|
var wr = WireRef(
|
||||||
|
orKind: WireRefKind.mine,
|
||||||
|
mine: WireRefMine(oid: opts.initialOid.get))
|
||||||
|
fut.complete rewriteRefIn(relay, turn.activeFacet, wr, imported)
|
||||||
|
else:
|
||||||
|
fut.complete(nil)
|
||||||
|
opts.nextLocalOid.map do (oid: Oid):
|
||||||
|
relay.nextLocalOid =
|
||||||
|
if oid == 0.Oid: 1.Oid
|
||||||
|
else: oid
|
||||||
|
fut
|
||||||
|
|
||||||
|
import std/[asyncdispatch, asyncnet]
|
||||||
|
from std/nativesockets import AF_UNIX, SOCK_STREAM, Protocol
|
||||||
|
|
||||||
|
import protocols/gatekeeper
|
||||||
|
|
||||||
|
type ShutdownEntity = ref object of Entity
|
||||||
|
|
||||||
|
method publish(e: ShutdownEntity; t: var Turn; v: Assertion; h: Handle) = discard
|
||||||
|
|
||||||
|
method retract(e: ShutdownEntity; turn: var Turn; h: Handle) =
|
||||||
|
stopActor(turn)
|
||||||
|
|
||||||
|
type
|
||||||
|
SturdyRef = sturdy.SturdyRef[Ref]
|
||||||
|
Resolve = gatekeeper.Resolve[Ref]
|
||||||
|
|
||||||
|
proc connectUnix*(turn: var Turn; path: string; cap: SturdyRef; bootProc: DuringProc) =
|
||||||
|
var socket = newAsyncSocket(
|
||||||
|
domain = AF_UNIX,
|
||||||
|
sockType = SOCK_STREAM,
|
||||||
|
protocol = cast[Protocol](0),
|
||||||
|
buffered = false)
|
||||||
|
proc socketWriter(packet: seq[byte]): Future[void] =
|
||||||
|
socket.send cast[string](packet)
|
||||||
|
const recvSize = 4096
|
||||||
|
var shutdownRef: Ref
|
||||||
|
let reenable = turn.activeFacet.preventInertCheck()
|
||||||
|
let connectionClosedRef = newRef(turn, ShutdownEntity())
|
||||||
|
proc setup(turn: var Turn; relay: Relay) =
|
||||||
|
let facet = turn.activeFacet
|
||||||
|
proc recvCb(pktFut: Future[string]) {.gcsafe.} =
|
||||||
|
let buf = cast[seq[byte]](pktFut.read)
|
||||||
|
if buf.len == 0:
|
||||||
|
run(facet) do (turn: var Turn): stopActor(turn)
|
||||||
|
else:
|
||||||
|
relay.recv(buf )
|
||||||
|
socket.recv(recvSize).addCallback(recvCb)
|
||||||
|
# TODO: should this need be callSoon?
|
||||||
|
socket.recv(recvSize).addCallback(recvCb)
|
||||||
|
turn.activeFacet.actor.atExit do (turn: var Turn): close(socket)
|
||||||
|
discard publish(turn, connectionClosedRef, true)
|
||||||
|
shutdownRef = newRef(turn, ShutdownEntity())
|
||||||
|
var fut = newFuture[void]"connectUnix"
|
||||||
|
connectUnix(socket, path).addCallback do (f: Future[void]):
|
||||||
|
read f
|
||||||
|
discard newActor("unix") do (turn: var Turn):
|
||||||
|
let relayFut = spawnRelay("unix", turn, RelayActorOptions(
|
||||||
|
packetWriter: socketWriter,
|
||||||
|
setup: setup,
|
||||||
|
initialOid: 0.Oid.some))
|
||||||
|
relayFut.addCallback do (refFut: Future[Ref]):
|
||||||
|
let gatekeeper = read refFut
|
||||||
|
run(gatekeeper.relay) do (turn: var Turn):
|
||||||
|
reenable()
|
||||||
|
discard publish(turn, shutdownRef, true)
|
||||||
|
proc duringCallback(turn: var Turn; ds: Preserve[Ref]): TurnAction =
|
||||||
|
let facet = facet(turn) do (turn: var Turn):
|
||||||
|
discard bootProc(turn, ds) # TODO: what to do with this?
|
||||||
|
proc action(turn: var Turn) =
|
||||||
|
stop(turn, facet)
|
||||||
|
result = action
|
||||||
|
var res = Resolve(
|
||||||
|
sturdyref: cap,
|
||||||
|
observer: embed newRef(turn, during(duringCallback)))
|
||||||
|
discard publish(turn, gatekeeper, res)
|
||||||
|
fut.complete()
|
||||||
|
asyncCheck(turn, fut)
|
|
@ -1,50 +1,45 @@
|
||||||
# SPDX-FileCopyrightText: ☭ 2021 Emery Hemingway
|
# SPDX-FileCopyrightText: ☭ 2021 Emery Hemingway
|
||||||
# SPDX-License-Identifier: Unlicense
|
# SPDX-License-Identifier: Unlicense
|
||||||
|
|
||||||
import std/[asyncdispatch, asyncfile, posix, random, strutils]
|
import std/[asyncdispatch, asyncfile, random, strutils]
|
||||||
import preserves
|
import preserves, preserves/parse
|
||||||
import syndicate, syndicate/protocols/schemas/simpleChatProtocol, syndicate/sturdy
|
import syndicate/protocols/[simpleChatProtocol, sturdy]
|
||||||
|
import syndicate/[actors, dataspaces, patterns, relay]
|
||||||
|
|
||||||
|
from syndicate/protocols/protocol import Handle
|
||||||
|
|
||||||
|
from os import getCurrentProcessId
|
||||||
|
|
||||||
randomize()
|
randomize()
|
||||||
|
|
||||||
syndicate chat:
|
const capStr = """<ref "syndicate" [] #x"a6480df5306611ddd0d3882b546e1977">"""
|
||||||
|
|
||||||
let me = "user_" & $rand(range[10..1000])
|
proc noOp(turn: var Turn) = discard
|
||||||
|
|
||||||
spawn "debug":
|
waitFor runActor("chat") do (turn: var Turn):
|
||||||
onAsserted(?s) do (s: Preserve):
|
|
||||||
echo " asserted ", s
|
|
||||||
onRetracted(?s) do (s: Preserve):
|
|
||||||
echo " retracted ", s
|
|
||||||
onMessage(?s) do (s: Preserve):
|
|
||||||
echo " message ", s
|
|
||||||
|
|
||||||
spawn "log":
|
var cap: SturdyRef[Ref]
|
||||||
during(present(?who)) do (who: string):
|
doAssert fromPreserve(cap, parsePreserves(capStr, Ref))
|
||||||
echo who, " joined"
|
|
||||||
onStop:
|
|
||||||
echo who, " left"
|
|
||||||
onMessage(says(?who, ?what)) do (who: string; what: string):
|
|
||||||
echo who, " says ", what
|
|
||||||
|
|
||||||
spawn "chat":
|
connectUnix(turn, "/run/syndicate/ds", cap) do (turn: var Turn; a: Assertion) -> TurnAction:
|
||||||
publish present(me)
|
let ds = unembed a
|
||||||
during (present(me)):
|
var
|
||||||
let
|
username: string
|
||||||
inputFacet = getCurrentFacet()
|
usernameHandle: Handle
|
||||||
af = newAsyncFile(AsyncFD STDIN_FILENO)
|
|
||||||
inputFacet.beginExternalTask()
|
|
||||||
proc readStdin() =
|
|
||||||
readline(af).addCallback do (f: Future[string]):
|
|
||||||
if f.failed:
|
|
||||||
inputFacet.endExternalTask()
|
|
||||||
else:
|
|
||||||
callSoon:
|
|
||||||
readStdin()
|
|
||||||
let line = read f
|
|
||||||
if line.len > 0:
|
|
||||||
let a = says(me, strip line)
|
|
||||||
send a
|
|
||||||
readStdin()
|
|
||||||
|
|
||||||
waitFor chat()
|
proc updateUsername(turn: var Turn; u: string) =
|
||||||
|
username = u
|
||||||
|
usernameHandle = replace(turn, ds,
|
||||||
|
usernameHandle, Present(username: username))
|
||||||
|
|
||||||
|
updateUsername(turn, "user" & $getCurrentProcessId())
|
||||||
|
echo "username updated?"
|
||||||
|
|
||||||
|
proc duringPresent(turn: var Turn; a: Assertion): TurnAction =
|
||||||
|
echo "observed ", a
|
||||||
|
noOp
|
||||||
|
discard observe(turn, ds, toPattern(Present), during(duringPresent))
|
||||||
|
|
||||||
|
echo "post-observe"
|
||||||
|
|
||||||
|
echo "actor completed"
|
||||||
|
|
Loading…
Reference in New Issue