From 77fbab89ddc83e97bbe99c2064334bdbc9b1faa7 Mon Sep 17 00:00:00 2001 From: Tony Garnock-Jones Date: Tue, 23 Feb 2021 15:53:42 +0100 Subject: [PATCH] Simpler treatment of Refs --- actor.ts | 64 ++++++++++++++++---------------------------------------- main.ts | 16 +++++++------- 2 files changed, 26 insertions(+), 54 deletions(-) diff --git a/actor.ts b/actor.ts index a9c2812..0f4894f 100644 --- a/actor.ts +++ b/actor.ts @@ -5,51 +5,20 @@ export type Handle = number; export type ExitReason = null | { ok: true } | { ok: false, err: Error }; export type LocalAction = (t: Turn) => void; -export const assert = Symbol('assert'); -export const retract = Symbol('retract'); -export const message = Symbol('message'); -export const sync = Symbol('sync'); - export interface Entity { - [assert]?(turn: Turn, assertion: Assertion, handle: Handle): void; - [retract]?(turn: Turn, handle: Handle): void; - [message]?(turn: Turn, body: Assertion): void; - [sync]?(turn: Turn, peer: Entity): void; + assert?(turn: Turn, assertion: Assertion, handle: Handle): void; + retract?(turn: Turn, handle: Handle): void; + message?(turn: Turn, body: Assertion): void; + sync?(turn: Turn, peer: Ref): void; } -export class Ref implements Entity { - readonly relay: Actor; - readonly target: Entity; - - constructor(relay: Actor, target: Entity) { - this.relay = relay; - this.target = target; - } - - [assert](turn: Turn, assertion: Assertion, handle: Handle): void { - this.target[assert]?.(turn, assertion, handle); - } - - [retract](turn: Turn, handle: Handle): void { - this.target[retract]?.(turn, handle); - } - - [message](turn: Turn, body: Assertion): void { - this.target[message]?.(turn, body); - } - - [sync](turn: Turn, peer: Ref) { - this.target[sync] ? this.target[sync]!(turn, peer) : turn.message(peer, true); - } -} - -type OutboundMap = Map; +export interface Ref { readonly relay: Actor, readonly target: Entity }; export class Actor { - readonly outbound: OutboundMap; + readonly outbound: Map; exitReason: ExitReason = null; - constructor(initialAssertions: OutboundMap = new Map()) { + constructor(initialAssertions = new Map()) { this.outbound = initialAssertions; } @@ -76,7 +45,7 @@ let nextHandle = 0; export class Turn { readonly actor: Actor; - readonly queues: Map = new Map(); + readonly queues = new Map(); static for(actor: Actor, f: LocalAction): void { const t = new Turn(actor); @@ -89,12 +58,12 @@ export class Turn { } ref(e: Entity): Ref { - return (e instanceof Ref) ? e : new Ref(this.actor, e); + return { relay: this.actor, target: e }; } spawn(bootProc: LocalAction, initialAssertions = new IdentitySet()): void { this.enqueue(this.actor, () => { - const newOutbound: OutboundMap = new Map(); + const newOutbound = new Map(); initialAssertions.forEach(key => { newOutbound.set(key, this.actor.outbound.get(key)!); // we trust initialAssertions this.actor.outbound.delete(key); @@ -112,7 +81,7 @@ export class Turn { const h = nextHandle++; this.enqueue(ref.relay, t => { this.actor.outbound.set(h, ref); - ref[assert]?.(t, assertion, h); + ref.target.assert?.(t, assertion, h); }); return h; } @@ -130,17 +99,20 @@ export class Turn { _retract(ref: Ref, handle: Handle): void { this.enqueue(ref.relay, t => { this.actor.outbound.delete(handle); - ref[retract]?.(t, handle); + ref.target.retract?.(t, handle); }); } sync(ref: Ref): Promise { - return new Promise(resolve => - this.enqueue(ref.relay, t => ref[sync]?.(t, this.ref({ [message]: resolve })))); + return new Promise(resolve => { + const k = this.ref({ message: resolve }); + this.enqueue(ref.relay, t => + ref.target.sync ? ref.target.sync!(t, k) : t.message(k, true)); + }); } message(ref: Ref, assertion: Assertion): void { - this.enqueue(ref.relay, t => ref[message]?.(t, assertion)); + this.enqueue(ref.relay, t => ref.target.message?.(t, assertion)); } enqueue(relay: Actor, a: LocalAction): void { diff --git a/main.ts b/main.ts index 772c67b..e63165e 100644 --- a/main.ts +++ b/main.ts @@ -1,4 +1,4 @@ -import { Actor, Assertion, Entity, Handle, Ref, Turn, assert, message, retract } from './actor.js'; +import { Actor, Assertion, Entity, Handle, Ref, Turn } from './actor.js'; import { Dictionary, IdentityMap, is, Record } from 'preserves'; import { Bag, ChangeDescription } from './bag'; @@ -9,7 +9,7 @@ class Dataspace implements Entity { readonly assertions = new Bag(); readonly subscriptions: Dictionary>> = new Dictionary(); - [assert](turn: Turn, rec: Assertion, handle: Handle): void { + assert(turn: Turn, rec: Assertion, handle: Handle): void { if (!Record.isRecord(rec)) return; this.handleMap.set(handle, rec); if (this.assertions.change(rec, +1) !== ChangeDescription.ABSENT_TO_PRESENT) return; @@ -27,7 +27,7 @@ class Dataspace implements Entity { seen.has(rec) || seen.set(rec, turn.assert(peer, rec))); } - [retract](turn: Turn, upstreamHandle: Handle): void { + retract(turn: Turn, upstreamHandle: Handle): void { const rec = this.handleMap.get(upstreamHandle); if (rec === void 0) return; this.handleMap.delete(upstreamHandle); @@ -46,7 +46,7 @@ class Dataspace implements Entity { } } - [message](turn: Turn, rec: Assertion): void { + message(turn: Turn, rec: Assertion): void { if (!Record.isRecord(rec)) return; this.subscriptions.get(rec.label)?.forEach((_seen, peer) => turn.message(peer, rec)); } @@ -70,7 +70,7 @@ Turn.for(new Actor(), async (t: Turn) => { } setValue(t, 0); t.assert(ds, Observe(SetBox.constructorInfo.label, t.ref({ - [message](t: Turn, [newValue]: [number]): void { + message(t: Turn, [newValue]: [number]): void { // console.log(`Box: got ${newValue}`); if (newValue % 25000 === 0) { const endTime = Date.now(); @@ -91,7 +91,7 @@ Turn.for(new Actor(), async (t: Turn) => { console.log('Spawning Client'); let count = 0; t.assert(ds, Observe(BoxState.constructorInfo.label, t.ref({ - [assert](t: Turn, [currentValue]: [number]): void { + assert(t: Turn, [currentValue]: [number]): void { // console.log(`Client: got ${currentValue}`); if (currentValue === LIMIT) { console.log(`Client: quitting at limit`); @@ -102,8 +102,8 @@ Turn.for(new Actor(), async (t: Turn) => { } }))); t.assert(ds, Observe(BoxState.constructorInfo.label, t.ref({ - [assert](_t: Turn, _assertion: Assertion): void { count++; }, - [retract](t: Turn, _handle: Handle) { + assert(_t: Turn, _assertion: Assertion): void { count++; }, + retract(t: Turn, _handle: Handle) { if (--count === 0) { console.log('Client: detected box termination'); t.quit();