Simpler treatment of Refs
This commit is contained in:
parent
ec5146a8a7
commit
77fbab89dd
64
actor.ts
64
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<Handle, Ref>;
|
||||
export interface Ref { readonly relay: Actor, readonly target: Entity };
|
||||
|
||||
export class Actor {
|
||||
readonly outbound: OutboundMap;
|
||||
readonly outbound: Map<Handle, Ref>;
|
||||
exitReason: ExitReason = null;
|
||||
|
||||
constructor(initialAssertions: OutboundMap = new Map()) {
|
||||
constructor(initialAssertions = new Map<Handle, Ref>()) {
|
||||
this.outbound = initialAssertions;
|
||||
}
|
||||
|
||||
|
@ -76,7 +45,7 @@ let nextHandle = 0;
|
|||
|
||||
export class Turn {
|
||||
readonly actor: Actor;
|
||||
readonly queues: Map<Actor, LocalAction[]> = new Map();
|
||||
readonly queues = new Map<Actor, LocalAction[]>();
|
||||
|
||||
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<Handle>()): void {
|
||||
this.enqueue(this.actor, () => {
|
||||
const newOutbound: OutboundMap = new Map();
|
||||
const newOutbound = new Map<Handle, Ref>();
|
||||
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<Turn> {
|
||||
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 {
|
||||
|
|
16
main.ts
16
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<Ref>();
|
||||
readonly subscriptions: Dictionary<Map<Ref, Dictionary<Handle>>> = new Dictionary();
|
||||
|
||||
[assert](turn: Turn, rec: Assertion, handle: Handle): void {
|
||||
assert(turn: Turn, rec: Assertion, handle: Handle): void {
|
||||
if (!Record.isRecord<Ref>(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<Ref>(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();
|
||||
|
|
Loading…
Reference in New Issue