Rename Ref to Cap

This commit is contained in:
Emery Hemingway 2023-07-24 16:13:36 +01:00
parent 4e0a36ef31
commit ce8e800187
13 changed files with 175 additions and 174 deletions

View File

@ -17,7 +17,7 @@ when defined(posix):
export patterns
export Actor, Assertion, Facet, Handle, Ref, Symbol, Turn, TurnAction,
export Actor, Assertion, Facet, Handle, Cap, Ref, Symbol, Turn, TurnAction,
`$`, addCallback, analyse, asyncCheck, bootDataspace,
facet, future, inFacet, message, newDataspace, onStop, publish,
retract, replace, run, spawn, stop, unembed, unpackLiterals
@ -38,7 +38,7 @@ proc `?`*[T](val: T): Pattern {.inline.} =
patterns.grab[T](val)
type
Observe* = dataspace.Observe[Ref]
Observe* = dataspace.Observe[Cap]
PublishProc = proc (turn: var Turn; v: Assertion; h: Handle) {.closure, gcsafe.}
RetractProc = proc (turn: var Turn; h: Handle) {.closure, gcsafe.}
MessageProc = proc (turn: var Turn; v: Assertion) {.closure, gcsafe.}
@ -136,7 +136,7 @@ proc wrapDuringHandler(turn, entryBody, exitBody: NimNode): NimNode =
`exitBody`
result = action
macro onPublish*(turn: untyped; ds: Ref; pattern: Pattern; handler: untyped) =
macro onPublish*(turn: untyped; ds: Cap; pattern: Pattern; handler: untyped) =
## Call `handler` when an assertion matching `pattern` is published at `ds`.
let
argCount = argumentCount(handler)
@ -148,7 +148,7 @@ macro onPublish*(turn: untyped; ds: Ref; pattern: Pattern; handler: untyped) =
`handlerProc`
discard observe(`turn`, `ds`, `pattern`, ClosureEntity(publishImpl: `handlerSym`))
macro onMessage*(turn: untyped; ds: Ref; pattern: Pattern; handler: untyped) =
macro onMessage*(turn: untyped; ds: Cap; pattern: Pattern; handler: untyped) =
## Call `handler` when an message matching `pattern` is broadcasted at `ds`.
let
argCount = argumentCount(handler)
@ -160,7 +160,7 @@ macro onMessage*(turn: untyped; ds: Ref; pattern: Pattern; handler: untyped) =
`handlerProc`
discard observe(`turn`, `ds`, `pattern`, ClosureEntity(messageImpl: `handlerSym`))
macro during*(turn: untyped; ds: Ref; pattern: Pattern; publishBody, retractBody: untyped) =
macro during*(turn: untyped; ds: Cap; pattern: Pattern; publishBody, retractBody: untyped) =
## Call `publishBody` when an assertion matching `pattern` is published to `ds` and
## call `retractBody` on retraction. Assertions that match `pattern` but are not
## convertable to the arguments of `publishBody` are silently discarded.
@ -178,7 +178,7 @@ macro during*(turn: untyped; ds: Ref; pattern: Pattern; publishBody, retractBody
`callbackProc`
discard observe(`turn`, `ds`, `pattern`, during(`callbackSym`))
macro during*(turn: untyped; ds: Ref; pattern: Pattern; publishBody: untyped) =
macro during*(turn: untyped; ds: Cap; pattern: Pattern; publishBody: untyped) =
## Variant of `during` without a retract body.
let
argCount = argumentCount(publishBody)
@ -190,7 +190,7 @@ macro during*(turn: untyped; ds: Ref; pattern: Pattern; publishBody: untyped) =
`callbackProc`
discard observe(`turn`, `ds`, `pattern`, during(`callbackSym`))
type BootProc = proc (ds: Ref; turn: var Turn) {.gcsafe.}
type BootProc = proc (ds: Cap; turn: var Turn) {.gcsafe.}
proc runActor*(name: string; bootProc: BootProc) =
## Run an `Actor` to completion.

View File

@ -27,27 +27,29 @@ generateIdType(TurnId)
type
Oid = sturdy.Oid
Assertion* = Preserve[Ref]
Caveat = sturdy.Caveat[Ref]
Assertion* = Preserve[Cap]
Caveat = sturdy.Caveat[Cap]
Attenuation = seq[Caveat]
Rewrite = sturdy.Rewrite[Ref]
Rewrite = sturdy.Rewrite[Cap]
AssertionRef* = ref object
value*: Preserve[Ref]
# if the Enity methods take a Preserve[Ref] object then the generated
value*: Preserve[Cap]
# if the Enity methods take a Preserve[Cap] object then the generated
# C code has "redefinition of struct" problems when orc is enabled
Entity* = ref object of RootObj
oid*: Oid # oid is how Entities are identified over the wire
Ref* {.unpreservable.} = ref object # TODO: rename
Cap* {.unpreservable.} = ref object
relay*: Facet
target*: Entity
attenuation*: Attenuation
Ref* {.deprecated: "Ref was renamed to Cap".} = Cap
OutboundAssertion = ref object
handle: Handle
peer: Ref
peer: Cap
established: bool
OutboundTable = Table[Handle, OutboundAssertion]
@ -111,7 +113,7 @@ when tracing:
method publish*(e: Entity; turn: var Turn; v: AssertionRef; h: Handle) {.base, gcsafe.} = discard
method retract*(e: Entity; turn: var Turn; h: Handle) {.base, gcsafe.} = discard
method message*(e: Entity; turn: var Turn; v: AssertionRef) {.base, gcsafe.} = discard
method sync*(e: Entity; turn: var Turn; peer: Ref) {.base, gcsafe.} = discard
method sync*(e: Entity; turn: var Turn; peer: Cap) {.base, gcsafe.} = discard
using
actor: Actor
@ -133,15 +135,15 @@ proc labels(f: Facet): string =
proc `$`*(f: Facet): string =
"<Facet:" & f.labels & ">"
proc `$`*(r: Ref): string =
proc `$`*(r: Cap): string =
"<Ref:" & r.relay.labels & ">"
proc `$`*(actor: Actor): string =
"<Actor:" & actor.name & ">" # TODO: ambigous
proc attenuate(r: Ref; a: Attenuation): Ref =
proc attenuate(r: Cap; a: Attenuation): Cap =
if a.len == 0: result = r
else: result = Ref(
else: result = Cap(
relay: r.relay,
target: r.target,
attenuation: a & r.attenuation)
@ -149,7 +151,7 @@ proc attenuate(r: Ref; a: Attenuation): Ref =
proc hash*(facet): Hash =
facet.id.hash
proc hash*(r: Ref): Hash = !$(r.relay.hash !& r.target.unsafeAddr.hash)
proc hash*(r: Cap): Hash = !$(r.relay.hash !& r.target.unsafeAddr.hash)
proc nextHandle(facet: Facet): Handle =
result = succ(facet.actor.handleAllocator[])
@ -163,7 +165,7 @@ proc enqueue(turn: var Turn; target: Facet; action: TurnAction) =
else:
turn.queues[target] = @[action]
type Bindings = Table[Preserve[Ref], Preserve[Ref]]
type Bindings = Table[Preserve[Cap], Preserve[Cap]]
proc match(bindings: var Bindings; p: Pattern; v: Assertion): bool =
case p.orKind
@ -181,7 +183,7 @@ proc match(bindings: var Bindings; p: Pattern; v: Assertion): bool =
result = v.isEmbedded
of PatternKind.Pbind:
if match(bindings, p.pbind.pattern, v):
bindings[toPreserve(p.pbind.pattern, Ref)] = v
bindings[toPreserve(p.pbind.pattern, Cap)] = v
result = true
of PatternKind.Pand:
for pp in p.pand.patterns:
@ -233,7 +235,7 @@ proc instantiate(t: Template; bindings: Bindings): Assertion =
result = embed(attenuate(v.embed, t.tattenuate.attenuation))
of TemplateKind.TRef:
let n = $t.tref.binding.int
try: result = bindings[toPreserve(n, Ref)]
try: result = bindings[toPreserve(n, Cap)]
except KeyError:
raise newException(ValueError, "unbound reference: " & n)
of TemplateKind.Lit:
@ -245,11 +247,11 @@ proc instantiate(t: Template; bindings: Bindings): Assertion =
for i, tt in t.tcompound.rec.fields:
result[i] = instantiate(tt, bindings)
of TCompoundKind.arr:
result = initSequence(t.tcompound.arr.items.len, Ref)
result = initSequence(t.tcompound.arr.items.len, Cap)
for i, tt in t.tcompound.arr.items:
result[i] = instantiate(tt, bindings)
of TCompoundKind.dict:
result = initDictionary(Ref)
result = initDictionary(Cap)
for key, tt in t.tcompound.dict.entries:
result[key] = instantiate(tt, bindings)
@ -275,7 +277,7 @@ proc runRewrites*(a: Attenuation; v: Assertion): Assertion =
result = examineAlternatives(stage, result)
if result.isFalse: break
proc publish(turn: var Turn; r: Ref; v: Assertion; h: Handle) =
proc publish(turn: var Turn; r: Cap; v: Assertion; h: Handle) =
var a = runRewrites(r.attenuation, v)
if not a.isFalse:
let e = OutboundAssertion(
@ -291,18 +293,18 @@ proc publish(turn: var Turn; r: Ref; v: Assertion; h: Handle) =
act.enqueue.event.target.oid = r.target.oid.toPreserve
act.enqueue.event.detail = trace.TurnEvent[void](orKind: TurnEventKind.assert)
act.enqueue.event.detail.assert.assertion.value.value =
contract(v) do (r: Ref) -> Preserve[void]:
contract(v) do (r: Cap) -> Preserve[void]:
discard
act.enqueue.event.detail.assert.handle = h
turn.desc.actions.add act
proc publish*(turn: var Turn; r: Ref; a: Assertion): Handle =
proc publish*(turn: var Turn; r: Cap; a: Assertion): Handle =
result = turn.facet.nextHandle()
publish(turn, r, a, result)
proc publish*[T](turn: var Turn; r: Ref; a: T): Handle =
publish(turn, r, toPreserve(a, Ref))
proc publish*[T](turn: var Turn; r: Cap; a: T): Handle =
publish(turn, r, toPreserve(a, Cap))
proc retract(turn: var Turn; e: OutboundAssertion) =
enqueue(turn, e.peer.relay) do (turn: var Turn):
@ -315,31 +317,31 @@ proc retract*(turn: var Turn; h: Handle) =
if turn.facet.outbound.pop(h, e):
turn.retract(e)
proc message*(turn: var Turn; r: Ref; v: Assertion) =
proc message*(turn: var Turn; r: Cap; v: Assertion) =
var a = runRewrites(r.attenuation, v)
if not a.isFalse:
enqueue(turn, r.relay) do (turn: var Turn):
r.target.message(turn, AssertionRef(value: a))
proc message*[T](turn: var Turn; r: Ref; v: T) =
message(turn, r, toPreserve(v, Ref))
proc message*[T](turn: var Turn; r: Cap; v: T) =
message(turn, r, toPreserve(v, Cap))
proc sync(turn: var Turn; e: Entity; peer: Ref) =
proc sync(turn: var Turn; e: Entity; peer: Cap) =
e.sync(turn, peer)
# or turn.message(peer, true) ?
proc sync*(turn: var Turn; r, peer: Ref) =
proc sync*(turn: var Turn; r, peer: Cap) =
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)
proc replace*[T](turn: var Turn; cap: Cap; h: Handle; v: T): Handle =
result = publish(turn, cap, v)
if h != default(Handle):
retract(turn, h)
proc replace*[T](turn: var Turn; `ref`: Ref; h: var Handle; v: T): Handle {.discardable.} =
proc replace*[T](turn: var Turn; cap: Cap; h: var Handle; v: T): Handle {.discardable.} =
var old = h
h = publish(turn, `ref`, v)
h = publish(turn, cap, v)
if old != default(Handle):
retract(turn, old)
h
@ -475,9 +477,9 @@ proc spawn*(name: string; turn: var Turn; bootProc: TurnAction; initialAssertion
run(actor, bootProc, newOutBound)
actor
proc newInertRef*(): Ref =
proc newInertCap*(): Cap =
let a = bootActor("inert") do (turn: var Turn): turn.stop()
Ref(relay: a.root)
Cap(relay: a.root)
proc atExit*(actor; action) = actor.exitHooks.add action
@ -532,9 +534,9 @@ proc run*(facet; action: TurnAction; zombieTurn = false) =
for facet, queue in queues:
for action in queue: run(facet, action)
proc run*(`ref`: Ref; action: TurnAction) =
## Convenience proc to run a `TurnAction` in the scope of a `Ref`.
run(`ref`.relay, action)
proc run*(cap: Cap; action: TurnAction) =
## Convenience proc to run a `TurnAction` in the scope of a `Cap`.
run(cap.relay, action)
proc addCallback*(fut: FutureBase; facet: Facet; act: TurnAction) =
## Add a callback to a `Future` that will be called at a later `Turn`
@ -592,13 +594,13 @@ proc freshen*(turn: var Turn, act: TurnAction) =
assert(turn.queues.len == 0, "Attempt to freshen a non-stale Turn")
run(turn.facet, act)
proc newRef*(relay: Facet; e: Entity): Ref =
Ref(relay: relay, target: e)
proc newCap*(relay: Facet; e: Entity): Cap =
Cap(relay: relay, target: e)
proc newRef*(turn; e: Entity): Ref =
Ref(relay: turn.facet, target: e)
proc newCap*(turn; e: Entity): Cap =
Cap(relay: turn.facet, target: e)
proc sync*(turn, refer: Ref, cb: proc(t: Turn) {.gcsafe.}) =
proc sync*(turn, refer: Cap, cb: proc(t: Turn) {.gcsafe.}) =
raiseAssert "not implemented"
proc future*(actor): Future[void] = actor.future

View File

@ -10,11 +10,11 @@ from syndicate/protocols/dataspace import Observe
export timer
type Observe = dataspace.Observe[Ref]
type Observe = dataspace.Observe[Cap]
proc now: float64 = getTime().toUnixFloat()
proc spawnTimers*(turn: var Turn; ds: Ref): Actor {.discardable.} =
proc spawnTimers*(turn: var Turn; ds: Cap): Actor {.discardable.} =
## Spawn a timer actor.
spawn("timer", turn) do (turn: var Turn):
@ -28,7 +28,7 @@ proc spawnTimers*(turn: var Turn; ds: Ref): Actor {.discardable.} =
run(facet) do (turn: var Turn):
discard publish(turn, ds, LaterThan(seconds: seconds))
template after*(turn: var Turn; ds: Ref; dur: Duration; act: untyped) =
template after*(turn: var Turn; ds: Cap; dur: Duration; act: untyped) =
## Execute `act` after some duration of time.
let later = now() + dur.inMilliseconds.float64 * 1_000.0
onPublish(turn, ds, ?LaterThan(seconds: later), act)

View File

@ -12,7 +12,7 @@ import hashlib/misc/blake2
import preserves
import ./protocols/sturdy
from ./actors import Ref
from ./actors import Cap
export `$`
@ -26,9 +26,9 @@ proc mint*[T](key: openarray[byte]; oid: Preserve[T]): SturdyRef[T] =
}.toDictionary,
)
proc mint*(): SturdyRef[Ref] =
proc mint*(): SturdyRef[Cap] =
var key: array[16, byte]
mint(key, toPreserve("syndicate", Ref))
mint(key, toPreserve("syndicate", Cap))
proc attenuate*[T](r: SturdyRef[T]; caveats: seq[Caveat]): SturdyRef[T] =
result = SturdyRef[T](

View File

@ -8,8 +8,8 @@ import ./actors, ./protocols/dataspace, ./skeletons
from ./protocols/protocol import Handle
type
Assertion = Preserve[Ref]
Observe = dataspace.Observe[Ref]
Assertion = Preserve[Cap]
Observe = dataspace.Observe[Cap]
Turn = actors.Turn
Dataspace {.final.} = ref object of Entity
@ -34,10 +34,10 @@ method retract(ds: Dataspace; turn: var Turn; h: Handle) {.gcsafe.} =
method message(ds: Dataspace; turn: var Turn; a: AssertionRef) {.gcsafe.} =
ds.index.deliverMessage(turn, a.value)
proc newDataspace*(turn: var Turn): Ref =
newRef(turn, Dataspace(index: initIndex()))
proc newDataspace*(turn: var Turn): Cap =
newCap(turn, Dataspace(index: initIndex()))
type BootProc = proc (ds: Ref; turn: var Turn) {.gcsafe.}
type BootProc = proc (ds: Cap; turn: var Turn) {.gcsafe.}
proc bootDataspace*(name: string; bootProc: BootProc): Actor =
bootActor(name) do (turn: var Turn):

View File

@ -8,7 +8,7 @@ import ./actors, ./patterns, ./protocols/dataspace
from ./protocols/protocol import Handle
type
Observe = dataspace.Observe[Ref]
Observe = dataspace.Observe[Cap]
Turn = actors.Turn
type
@ -50,5 +50,5 @@ method retract(de: DuringEntity; turn: var Turn; h: Handle) =
proc during*(cb: DuringProc): DuringEntity = DuringEntity(cb: cb)
proc observe*(turn: var Turn; ds: Ref; pat: Pattern; e: Entity): Handle =
publish(turn, ds, Observe(pattern: pat, observer: newRef(turn, e)))
proc observe*(turn: var Turn; ds: Cap; pat: Pattern; e: Entity): Handle =
publish(turn, ds, Observe(pattern: pat, observer: newCap(turn, e)))

View File

@ -3,43 +3,43 @@
import std/[hashes, tables]
from ./actors import Ref, hash
from ./actors import Cap, hash
from ./protocols/sturdy import Oid
proc hash(r: Ref): Hash = !$(r.relay.hash !& r.target.unsafeAddr.hash)
proc hash(r: Cap): Hash = !$(r.relay.hash !& r.target.unsafeAddr.hash)
type
Membrane* = object
## Bidirectional mapping between `Oid` and `Ref` values.
## Bidirectional mapping between `Oid` and `Cap` values.
## https://synit.org/book/protocol.html#membranes
byOid: Table[Oid, WireSymbol]
byRef: Table[Ref, WireSymbol]
byCap: Table[Cap, WireSymbol]
WireSymbol* = ref object
oid: Oid
`ref`: Ref
cap: Cap
count: int
proc oid*(sym: WireSymbol): Oid = sym.oid
proc `ref`*(sym: WireSymbol): Ref = sym.ref
proc cap*(sym: WireSymbol): Cap = sym.cap
proc grab*(mem: Membrane; key: Oid): WireSymbol =
## Grab a `WireSymbol` from a `Membrane`.
mem.byOid.getOrDefault(key)
proc grab*(mem: Membrane; key: Ref): WireSymbol =
proc grab*(mem: Membrane; key: Cap): WireSymbol =
## Grab a `WireSymbol` from a `Membrane`.
mem.byRef.getOrDefault(key)
mem.byCap.getOrDefault(key)
proc drop*(mem: var Membrane; sym: WireSymbol) =
## Drop a `WireSymbol` from a `Membrane`.
dec sym.count
if sym.count < 1:
mem.byOid.del sym.oid
mem.byRef.del sym.`ref`
mem.byCap.del sym.cap
proc newWireSymbol*(mem: var Membrane; o: Oid; r: Ref): WireSymbol =
proc newWireSymbol*(mem: var Membrane; o: Oid; r: Cap): WireSymbol =
## Allocate a `WireSymbol` at a `Membrane`.
result = WireSymbol(oid: o, `ref`: r, count: 1)
result = WireSymbol(oid: o, cap: r, count: 1)
mem.byOid[result.oid] = result
mem.byRef[result.`ref`] = result
mem.byCap[result.cap] = result

View File

@ -5,20 +5,20 @@ import std/[algorithm, options, sequtils, tables, typetraits]
import preserves
import ./protocols/dataspacePatterns
from ./actors import Ref
from ./actors import Cap
export dataspacePatterns.`$`, PatternKind, DCompoundKind, AnyAtomKind
type
Value = Preserve[Ref]
AnyAtom = dataspacePatterns.AnyAtom[Ref]
DBind = dataspacePatterns.DBind[Ref]
DCompound = dataspacePatterns.DCompound[Ref]
DCompoundArr = dataspacePatterns.DCompoundArr[Ref]
DCompoundDict = dataspacePatterns.DCompoundDict[Ref]
DCompoundRec = dataspacePatterns.DCompoundRec[Ref]
DLit = dataspacePatterns.DLit[Ref]
Pattern* = dataspacePatterns.Pattern[Ref]
Value = Preserve[Cap]
AnyAtom = dataspacePatterns.AnyAtom[Cap]
DBind = dataspacePatterns.DBind[Cap]
DCompound = dataspacePatterns.DCompound[Cap]
DCompoundArr = dataspacePatterns.DCompoundArr[Cap]
DCompoundDict = dataspacePatterns.DCompoundDict[Cap]
DCompoundRec = dataspacePatterns.DCompoundRec[Cap]
DLit = dataspacePatterns.DLit[Cap]
Pattern* = dataspacePatterns.Pattern[Cap]
iterator orderedEntries*(dict: DCompoundDict): (Value, Pattern) =
## Iterate a `DCompoundDict` in Preserves order.
@ -88,7 +88,7 @@ proc grab*[T](pr: Preserve[T]): Pattern =
drop()
else:
DCompoundRec(
label: cast[Preserve[Ref]](pr.label), # TODO: don't cast like this
label: cast[Preserve[Cap]](pr.label), # TODO: don't cast like this
fields: map[Preserve[T], Pattern](pr.fields, grab)).toPattern
of pkSequence:
DCompoundArr(items: map(pr.sequence, grab)).toPattern
@ -96,7 +96,7 @@ proc grab*[T](pr: Preserve[T]): Pattern =
raiseAssert "cannot construct a pattern over a set literal"
of pkDictionary:
var dict = DCompoundDict()
for key, val in pr.pairs: dict.entries[cast[Preserve[Ref]](key)] = grab val
for key, val in pr.pairs: dict.entries[cast[Preserve[Cap]](key)] = grab val
dict.toPattern
of pkEmbedded:
# TODO: can patterns be constructed over embedded literals?
@ -110,20 +110,20 @@ proc grab*[T](val: T): Pattern =
$grab(true) == "<lit #t>"
$grab(3.14) == "<lit 3.14>"
$grab([0, 1, 2, 3]) == "<arr [<lit 0> <lit 1> <lit 2> <lit 3>]>"
grab (toPreserve(val, Ref))
grab (toPreserve(val, Cap))
proc patternOfType(typ: static typedesc; `bind`: static bool): Pattern =
when typ is ref:
patternOfType(pointerBase(typ), `bind`)
elif typ.hasPreservesRecordPragma:
var rec = DCompoundRec(label: typ.recordLabel.tosymbol(Ref))
var rec = DCompoundRec(label: typ.recordLabel.tosymbol(Cap))
for _, f in fieldPairs(default typ):
add(rec.fields, patternOfType(typeof f, `bind`))
result = rec.toPattern
elif typ.hasPreservesDictionaryPragma:
var dict = DCompoundDict()
for key, val in fieldPairs(default typ):
dict.entries[toSymbol(key, Ref)] = patternOfType(typeof val, `bind`)
dict.entries[toSymbol(key, Cap)] = patternOfType(typeof val, `bind`)
dict.toPattern
elif typ is tuple:
var arr = DCompoundArr()
@ -191,7 +191,7 @@ proc grab*(typ: static typedesc; bindings: sink openArray[(int, Pattern)]): Patt
when typ is ref:
grab(pointerBase(typ), bindings)
elif typ.hasPreservesRecordPragma:
var rec = DCompoundRec(label: typ.recordLabel.tosymbol(Ref))
var rec = DCompoundRec(label: typ.recordLabel.tosymbol(Cap))
rec.fields.setLen(fieldCount typ)
var i: int
for _, f in fieldPairs(default typ):
@ -269,7 +269,7 @@ proc inject*(pat: Pattern; bindings: openArray[(int, Pattern)]): Pattern =
var offset = 0
inject(pat, bindings, offset)
proc inject*(pat: Pattern; bindings: openArray[(Preserve[Ref], Pattern)]): Pattern =
proc inject*(pat: Pattern; bindings: openArray[(Preserve[Cap], Pattern)]): Pattern =
## Inject `bindings` into a dictionary pattern.
assert pat.orKind == PatternKind.DCompound
assert pat.dcompound.orKind == DCompoundKind.dict
@ -277,12 +277,12 @@ proc inject*(pat: Pattern; bindings: openArray[(Preserve[Ref], Pattern)]): Patte
for (key, val) in bindings:
result.dcompound.dict.entries[key] = val
proc recordPattern*(label: Preserve[Ref], fields: varargs[Pattern]): Pattern =
proc recordPattern*(label: Preserve[Cap], fields: varargs[Pattern]): Pattern =
runnableExamples:
from std/unittest import check
import syndicate/actors, preserves
check:
$recordPattern("Says".toSymbol(Ref), grab(), grab()) ==
$recordPattern("Says".toSymbol(Cap), grab(), grab()) ==
"""<rec Says [<bind <_>> <bind <_>>]>"""
DCompoundRec(label: label, fields: fields.toSeq).toPattern
@ -298,7 +298,7 @@ type
func walk(result: var Analysis; path: var Path; p: Pattern)
func walk(result: var Analysis; path: var Path; key: int|Value; pat: Pattern) =
path.add(key.toPreserve(Ref))
path.add(key.toPreserve(Cap))
walk(result, path, pat)
discard path.pop
@ -318,7 +318,7 @@ func walk(result: var Analysis; path: var Path; p: Pattern) =
of PatternKind.DDiscard: discard
of PatternKind.DLit:
result.constPaths.add(path)
result.constValues.add(p.dlit.value.toPreserve(Ref))
result.constValues.add(p.dlit.value.toPreserve(Cap))
func analyse*(p: Pattern): Analysis =
var path: Path

View File

@ -19,7 +19,7 @@ type Oid = sturdy.Oid
type
Value = Preserve[void]
Assertion = Preserve[Ref]
Assertion = Preserve[Cap]
WireRef = sturdy.WireRef[void]
Turn = actors.Turn
@ -42,7 +42,7 @@ type
SyncPeerEntity = ref object of Entity
relay: Relay
peer: Ref
peer: Cap
handleMap: Table[Handle, Handle]
e: WireSymbol
@ -51,7 +51,7 @@ type
label: string
relay: Relay
proc releaseRefOut(r: Relay; e: WireSymbol) =
proc releaseCapOut(r: Relay; e: WireSymbol) =
r.exported.drop e
method publish(spe: SyncPeerEntity; t: var Turn; a: AssertionRef; h: Handle) =
@ -64,22 +64,22 @@ method retract(se: SyncPeerEntity; t: var Turn; h: Handle) =
method message(se: SyncPeerEntity; t: var Turn; a: AssertionRef) =
if not se.e.isNil:
se.relay.releaseRefOut(se.e)
se.relay.releaseCapOut(se.e)
message(t, se.peer, a.value)
method sync(se: SyncPeerEntity; t: var Turn; peer: Ref) =
method sync(se: SyncPeerEntity; t: var Turn; peer: Cap) =
sync(t, se.peer, peer)
proc newSyncPeerEntity(r: Relay; p: Ref): SyncPeerEntity =
proc newSyncPeerEntity(r: Relay; p: Cap): SyncPeerEntity =
SyncPeerEntity(relay: r, peer: p)
proc rewriteRefOut(relay: Relay; `ref`: Ref; exported: var seq[WireSymbol]): WireRef =
if `ref`.target of RelayEntity and `ref`.target.RelayEntity.relay == relay and `ref`.attenuation.len == 0:
WireRef(orKind: WireRefKind.yours, yours: WireRefYours[void](oid: `ref`.target.oid))
proc rewriteCapOut(relay: Relay; cap: Cap; exported: var seq[WireSymbol]): WireRef =
if cap.target of RelayEntity and cap.target.RelayEntity.relay == relay and cap.attenuation.len == 0:
WireRef(orKind: WireRefKind.yours, yours: WireRefYours[void](oid: cap.target.oid))
else:
var ws = grab(relay.exported, `ref`)
var ws = grab(relay.exported, cap)
if ws.isNil:
ws = newWireSymbol(relay.exported, relay.nextLocalOid, `ref`)
ws = newWireSymbol(relay.exported, relay.nextLocalOid, cap)
inc relay.nextLocalOid
exported.add ws
WireRef(
@ -89,8 +89,8 @@ proc rewriteRefOut(relay: Relay; `ref`: Ref; exported: var seq[WireSymbol]): Wir
proc rewriteOut(relay: Relay; v: Assertion):
tuple[rewritten: Value, exported: seq[WireSymbol]] {.gcsafe.} =
var exported: seq[WireSymbol]
result.rewritten = contract(v) do (r: Ref) -> Value:
rewriteRefOut(relay, r, exported).toPreserve
result.rewritten = contract(v) do (r: Cap) -> Value:
rewriteCapOut(relay, r, exported).toPreserve
result.exported = exported
proc register(relay: Relay; v: Assertion; h: Handle): tuple[rewritten: Value, exported: seq[WireSymbol]] =
@ -100,7 +100,7 @@ proc register(relay: Relay; v: Assertion; h: Handle): tuple[rewritten: Value, ex
proc deregister(relay: Relay; h: Handle) =
var outbound: seq[WireSymbol]
if relay.outboundAssertions.pop(h, outbound):
for e in outbound: releaseRefOut(relay, e)
for e in outbound: releaseCapOut(relay, e)
proc send(r: Relay; pkt: sink Packet): Future[void] =
assert(not r.packetWriter.isNil, "missing packetWriter proc")
@ -141,11 +141,11 @@ method message(re: RelayEntity; turn: var Turn; msg: AssertionRef) {.gcsafe.} =
if len(exported) == 0:
re.send Event(orKind: EventKind.Message, message: Message(body: value))
method sync(re: RelayEntity; turn: var Turn; peer: Ref) {.gcsafe.} =
method sync(re: RelayEntity; turn: var Turn; peer: Cap) {.gcsafe.} =
var
peerEntity = newSyncPeerEntity(re.relay, peer)
exported: seq[WireSymbol]
discard rewriteRefOut(re.relay, turn.newRef(peerEntity), exported)
discard rewriteCapOut(re.relay, turn.newCap(peerEntity), exported)
# TODO: discard?
peerEntity.e = exported[0]
re.send Event(orKind: EventKind.Sync)
@ -157,24 +157,24 @@ using
relay: Relay
facet: Facet
proc lookupLocal(relay; oid: Oid): Ref =
proc lookupLocal(relay; oid: Oid): Cap =
let sym = relay.exported.grab oid
if sym.isNil: newInertRef()
else: sym.`ref`
if sym.isNil: newInertCap()
else: sym.cap
proc isInert(r: Ref): bool =
proc isInert(r: Cap): bool =
r.target.isNil
proc rewriteRefIn(relay; facet; n: WireRef, imported: var seq[WireSymbol]): Ref =
proc rewriteCapIn(relay; facet; n: WireRef, imported: var seq[WireSymbol]): Cap =
case n.orKind
of WireRefKind.mine:
var e = relay.imported.grab(n.mine.oid)
if e.isNil: e = newWireSymbol(
relay.imported,
n.mine.oid,
newRef(facet, newRelayEntity("rewriteRefIn", relay, n.mine.oid)))
newCap(facet, newRelayEntity("rewriteCapIn", relay, n.mine.oid)))
imported.add e
result = e.`ref`
result = e.cap
of WireRefKind.yours:
let r = relay.lookupLocal(n.yours.oid)
if n.yours.attenuation.len == 0 or r.isInert: result = r
@ -187,16 +187,16 @@ proc rewriteIn(relay; facet; v: Value):
var wr: WireRef
if not fromPreserve(wr, pr):
raiseAssert "expansion of embedded value failed"
rewriteRefIn(relay, facet, wr, imported).toPreserve(Ref)
rewriteCapIn(relay, facet, wr, imported).toPreserve(Cap)
result.imported = imported
proc close(r: Relay) = discard
proc dispatch*(relay: Relay; turn: var Turn; `ref`: Ref; event: Event) {.gcsafe.} =
proc dispatch*(relay: Relay; turn: var Turn; cap: Cap; event: Event) {.gcsafe.} =
case event.orKind
of EventKind.Assert:
let (a, imported) = rewriteIn(relay, turn.facet, event.assert.assertion)
relay.inboundAssertions[event.assert.handle] = (publish(turn, `ref`, a), imported,)
relay.inboundAssertions[event.assert.handle] = (publish(turn, cap, a), imported,)
of EventKind.Retract:
let remoteHandle = event.retract.handle
@ -208,14 +208,14 @@ proc dispatch*(relay: Relay; turn: var Turn; `ref`: Ref; event: Event) {.gcsafe.
of EventKind.Message:
let (a, imported) = rewriteIn(relay, turn.facet, event.message.body)
assert imported.len == 0, "Cannot receive transient reference"
turn.message(`ref`, a)
turn.message(cap, 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):
let k = relay.rewriteCapIn(turn, evenr.sync.peer, imported)
turn.sync(cap) do (turn: var Turn):
turn.message(k, true)
for e in imported: relay.imported.del e
]#
@ -233,7 +233,7 @@ proc dispatch*(relay: Relay; v: Value) {.gcsafe.} =
if not r.isInert:
dispatch(relay, t, r, te.event)
else:
stderr.writeLine("discarding event for unknown Ref; ", te.event)
stderr.writeLine("discarding event for unknown Cap; ", te.event)
of PacketKind.Error:
# https://synit.org/book/protocol.html#error-packets
when defined(posix):
@ -252,7 +252,7 @@ type
untrusted*: bool
RelayActorOptions* = object of RelayOptions
initialOid*: Option[Oid]
initialRef*: Ref
initialCap*: Cap
nextLocalOid*: Option[Oid]
proc newRelay(turn: var Turn; opts: RelayOptions; setup: RelaySetup): Relay =
@ -263,19 +263,19 @@ proc newRelay(turn: var Turn; opts: RelayOptions; setup: RelaySetup): Relay =
discard result.facet.preventInertCheck()
setup(turn, result)
proc spawnRelay*(name: string; turn: var Turn; opts: RelayActorOptions; setup: RelaySetup): Future[Ref] =
var fut = newFuture[Ref]"spawnRelay"
proc spawnRelay*(name: string; turn: var Turn; opts: RelayActorOptions; setup: RelaySetup): Future[Cap] =
var fut = newFuture[Cap]"spawnRelay"
discard spawn(name, turn) do (turn: var Turn):
let relay = newRelay(turn, opts, setup)
if not opts.initialRef.isNil:
if not opts.initialCap.isNil:
var exported: seq[WireSymbol]
discard rewriteRefOut(relay, opts.initialRef, exported)
discard rewriteCapOut(relay, opts.initialCap, 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.facet, wr, imported)
fut.complete rewriteCapIn(relay, turn.facet, wr, imported)
else:
fut.complete(nil)
opts.nextLocalOid.map do (oid: Oid):
@ -295,23 +295,23 @@ type ShutdownEntity* = ref object of Entity
method retract(e: ShutdownEntity; turn: var Turn; h: Handle) =
stopActor(turn)
type ConnectProc* = proc (turn: var Turn; ds: Ref) {.gcsafe.}
type ConnectProc* = proc (turn: var Turn; ds: Cap) {.gcsafe.}
export Tcp
when defined(posix):
export Unix
proc connect*(turn: var Turn; socket: AsyncSocket; step: Preserve[Ref]; bootProc: ConnectProc) =
proc connect*(turn: var Turn; socket: AsyncSocket; step: Preserve[Cap]; bootProc: ConnectProc) =
## Relay a dataspace over an open `AsyncSocket`.
## *`bootProc` may be called multiple times for multiple remote gatekeepers.*
proc socketWriter(packet: sink Packet): Future[void] =
socket.send(cast[string](encode(packet)))
const recvSize = 0x2000
var shutdownRef: Ref
var shutdownCap: Cap
let
reenable = turn.facet.preventInertCheck()
connectionClosedRef = newRef(turn, ShutdownEntity())
connectionClosedCap = newCap(turn, ShutdownEntity())
fut = newFuture[void]"connect"
discard bootActor("socket") do (turn: var Turn):
var ops = RelayActorOptions(
@ -336,18 +336,18 @@ when defined(posix):
socket.recv(recvSize).addCallback(recvCb)
socket.recv(recvSize).addCallback(recvCb)
turn.facet.actor.atExit do (turn: var Turn): close(socket)
discard publish(turn, connectionClosedRef, true)
shutdownRef = newRef(turn, ShutdownEntity())
discard publish(turn, connectionClosedCap, true)
shutdownCap = newCap(turn, ShutdownEntity())
addCallback(refFut) do ():
let gatekeeper = read refFut
run(gatekeeper.relay) do (turn: var Turn):
reenable()
discard publish(turn, shutdownRef, true)
discard publish(turn, shutdownCap, true)
proc duringCallback(turn: var Turn; a: Assertion; h: Handle): TurnAction =
let facet = inFacet(turn) do (turn: var Turn):
var
accepted: ResolvedAccepted[Ref]
rejected: Rejected[Ref]
accepted: ResolvedAccepted[Cap]
rejected: Rejected[Cap]
if fromPreserve(accepted, a):
bootProc(turn, accepted.responderSession)
elif fromPreserve(rejected, a):
@ -357,14 +357,14 @@ when defined(posix):
proc action(turn: var Turn) =
stop(turn, facet)
result = action
discard publish(turn, gatekeeper, Resolve[Ref](
discard publish(turn, gatekeeper, Resolve[Cap](
step: step,
observer: newRef(turn, during(duringCallback)),
observer: newCap(turn, during(duringCallback)),
))
fut.complete()
asyncCheck(turn, fut)
proc connect*(turn: var Turn; transport: Tcp; step: Preserve[Ref]; bootProc: ConnectProc) =
proc connect*(turn: var Turn; transport: Tcp; step: Preserve[Cap]; bootProc: ConnectProc) =
## Relay a dataspace over TCP.
## *`bootProc` may be called multiple times for multiple remote gatekeepers.*
let socket = newAsyncSocket(
@ -376,7 +376,7 @@ when defined(posix):
addCallback(fut, turn) do (turn: var Turn):
connect(turn, socket, step, bootProc)
proc connect*(turn: var Turn; transport: Unix; step: Preserve[Ref]; bootProc: ConnectProc) =
proc connect*(turn: var Turn; transport: Unix; step: Preserve[Cap]; bootProc: ConnectProc) =
## Relay a dataspace over a UNIX socket.
## *`bootProc` may be called multiple times for multiple remote gatekeepers.*
let socket = newAsyncSocket(
@ -392,7 +392,7 @@ when defined(posix):
const stdinReadSize = 128
proc connectStdio*(ds: Ref; turn: var Turn) =
proc connectStdio*(ds: Cap; turn: var Turn) =
## Connect to an external dataspace over stdin and stdout.
proc stdoutWriter(packet: sink Packet): Future[void] {.async.} =
var buf = encode(packet)
@ -400,7 +400,7 @@ when defined(posix):
flushFile(stdout)
var opts = RelayActorOptions(
packetWriter: stdoutWriter,
initialRef: ds,
initialCap: ds,
initialOid: 0.Oid.some)
asyncCheck spawnRelay("stdio", turn, opts) do (turn: var Turn; relay: Relay):
let

View File

@ -9,9 +9,9 @@ import ./actors, ./bags, ./patterns
import ./protocols/dataspacePatterns
type
DCompound = dataspacePatterns.DCompound[Ref]
Pattern = dataspacePatterns.Pattern[Ref]
Value = Preserve[Ref]
DCompound = dataspacePatterns.DCompound[Cap]
Pattern = dataspacePatterns.Pattern[Cap]
Value = Preserve[Cap]
Path = seq[Value]
ClassKind = enum classNone, classRecord, classSequence, classDictionary
Class = object
@ -61,7 +61,7 @@ type
ObserverGroup = ref object # Endpoints
cachedCaptures: Bag[Captures]
observers: Table[Ref, TableRef[Captures, Handle]]
observers: Table[Cap, TableRef[Captures, Handle]]
Leaf = ref object
cache: AssertionCache
@ -140,7 +140,6 @@ proc modify(node: Node; turn: var Turn; outerValue: Value; event: EventKind;
proc walk(cont: Continuation; turn: var Turn) =
modCont(cont, outerValue)
assert not cont.isEmpty()
for constPaths, constValMap in cont.leafMap.pairs:
let constVals = projectPaths(outerValue, constPaths)
if constVals.isSome:
@ -180,7 +179,7 @@ proc modify(node: Node; turn: var Turn; outerValue: Value; event: EventKind;
if event == removedEvent and nextNode.isEmpty:
table.del(nextClass)
walk(node, turn, @[@[outerValue].toPreserve(Ref)])
walk(node, turn, @[@[outerValue].toPreserve(Cap)])
proc getOrNew[A, B, C](t: var Table[A, TableRef[B, C]], k: A): TableRef[B, C] =
result = t.getOrDefault(k)
@ -192,10 +191,10 @@ iterator pairs(dc: DCompound): (Value, Pattern) =
case dc.orKind
of DCompoundKind.rec:
for i, p in dc.rec.fields:
yield (toPreserve(i, Ref), p,)
yield (toPreserve(i, Cap), p,)
of DCompoundKind.arr:
for i, p in dc.arr.items:
yield (toPreserve(i, Ref), p,)
yield (toPreserve(i, Cap), p,)
of DCompoundKind.dict:
for pair in dc.dict.entries.pairs:
yield pair
@ -229,7 +228,7 @@ proc extendWalk(node: Node; popCount: Natural; stepIndex: Value; pat: Pattern; p
proc extend(node: var Node; pat: Pattern): Continuation =
var path: Path
extendWalk(node, 0, toPreserve(0, Ref), pat, path).nextNode.continuation
extendWalk(node, 0, toPreserve(0, Cap), pat, path).nextNode.continuation
type
Index* = object
@ -250,7 +249,7 @@ proc getEndpoints(leaf: Leaf; capturePaths: Paths): ObserverGroup =
if captures.isSome:
discard result.cachedCaptures.change(get captures, +1)
proc add*(index: var Index; turn: var Turn; pattern: Pattern; observer: Ref) =
proc add*(index: var Index; turn: var Turn; pattern: Pattern; observer: Cap) =
let
cont = index.root.extend(pattern)
analysis = analyse pattern
@ -263,7 +262,7 @@ proc add*(index: var Index; turn: var Turn; pattern: Pattern; observer: Ref) =
captureMap[capture] = publish(turn, observer, capture)
endpoints.observers[observer] = captureMap
proc remove*(index: var Index; turn: var Turn; pattern: Pattern; observer: Ref) =
proc remove*(index: var Index; turn: var Turn; pattern: Pattern; observer: Cap) =
let
cont = index.root.extend(pattern)
analysis = analyse pattern
@ -295,7 +294,7 @@ proc adjustAssertion(index: var Index; turn: var Turn; outerValue: Value; delta:
let change = group.cachedCaptures.change(vs, +1)
if change == cdAbsentToPresent:
for (observer, captureMap) in group.observers.pairs:
captureMap[vs] = publish(turn, observer, vs.toPreserve(Ref))
captureMap[vs] = publish(turn, observer, vs.toPreserve(Cap))
# TODO: this handle is coming from the facet?
modify(index.root, turn, outerValue, addedEvent, modContinuation, modLeaf, modObserver)
of cdPresentToAbsent:

View File

@ -10,7 +10,7 @@ type
Says {.preservesRecord: "Says".} = object
who, what: string
proc readStdin(facet: Facet; ds: Ref; username: string) =
proc readStdin(facet: Facet; ds: Cap; username: string) =
let file = openAsync("/dev/stdin")
onStop(facet) do (turn: var Turn): close(file)
close(stdin)
@ -22,7 +22,7 @@ proc readStdin(facet: Facet; ds: Ref; username: string) =
readLine()
readLine()
proc chat(turn: var Turn; ds: Ref; username: string) =
proc chat(turn: var Turn; ds: Cap; username: string) =
during(turn, ds, ?Present) do (who: string):
echo who, " joined"
do:
@ -37,7 +37,7 @@ proc chat(turn: var Turn; ds: Ref; username: string) =
proc main =
var
transport: Preserve[void]
cap: Preserve[Ref]
cap: Preserve[Cap]
username = getEnv("USER")
calledWithArguments = false
for kind, key, val in getopt():
@ -47,20 +47,20 @@ proc main =
of "address", "transport":
transport = parsePreserves(val)
of "cap", "sturdy":
cap = parsePreserves(val, Ref)
cap = parsePreserves(val, Cap)
of "user", "username":
username = val
if calledWithArguments:
runActor("chat") do (root: Ref; turn: var Turn):
runActor("chat") do (root: Cap; turn: var Turn):
var
unixAddr: transportAddress.Unix
tcpAddr: transportAddress.Tcp
if fromPreserve(unixAddr, transport):
connect(turn, unixAddr, cap) do (turn: var Turn; ds: Ref):
connect(turn, unixAddr, cap) do (turn: var Turn; ds: Cap):
chat(turn, ds, username)
elif fromPreserve(tcpAddr, transport):
connect(turn, tcpAddr, cap) do (turn: var Turn; ds: Ref):
connect(turn, tcpAddr, cap) do (turn: var Turn; ds: Cap):
chat(turn, ds, username)
main()

View File

@ -5,7 +5,7 @@ import std/unittest
import preserves, syndicate
from syndicate/protocols/dataspace import Observe
type Observe = dataspace.Observe[Ref]
type Observe = dataspace.Observe[Cap]
import ./test_schema
@ -16,9 +16,9 @@ test "patterns":
let
value = @["alles", "in", "ordnung"]
observer = toPreserve(Observe(pattern: inject(?Foo, { 0: ?value })), Ref)
have = capture(observerPat, observer).toPreserve(Ref).unpackLiterals
want = [value.toPreserve(Ref)].toPreserve(Ref)
observer = toPreserve(Observe(pattern: inject(?Foo, { 0: ?value })), Cap)
have = capture(observerPat, observer).toPreserve(Cap).unpackLiterals
want = [value.toPreserve(Cap)].toPreserve(Cap)
check(have == want)
type Record {.preservesDictionary.} = object
@ -27,10 +27,10 @@ type Record {.preservesDictionary.} = object
test "dictionaries":
let pat = ?Record
echo pat
var source = initDictionary(Ref)
source["b".toSymbol(Ref)] = 2.toPreserve(Ref)
source["c".toSymbol(Ref)] = 3.toPreserve(Ref)
source["a".toSymbol(Ref)] = 1.toPreserve(Ref)
var source = initDictionary(Cap)
source["b".toSymbol(Cap)] = 2.toPreserve(Cap)
source["c".toSymbol(Cap)] = 3.toPreserve(Cap)
source["a".toSymbol(Cap)] = 1.toPreserve(Cap)
let values = capture(pat, source)
check $values == "@[1, 2, 3]"

View File

@ -6,7 +6,7 @@ import syndicate, syndicate/actors/timers
proc now: float64 = getTime().toUnixFloat()
runActor("test_timers") do (ds: Ref; turn: var Turn):
runActor("test_timers") do (ds: Cap; turn: var Turn):
onPublish(turn, ds, ?LaterThan(seconds: now()+1.0)) do:
stderr.writeLine "slept one second once"
onPublish(turn, ds, ?LaterThan(seconds: now()+1.0)) do: