It isn't really sensible to have a Ref for non-Entities
This commit is contained in:
parent
ecef864793
commit
cd7efd615e
29
actor.ts
29
actor.ts
|
@ -1,6 +1,6 @@
|
|||
import { IdentitySet, Value } from 'preserves';
|
||||
|
||||
export type Assertion = Value<Ref<Entity>>;
|
||||
export type Assertion = Value<Ref>;
|
||||
|
||||
export type Handle = number;
|
||||
|
||||
|
@ -16,21 +16,21 @@ export interface Entity {
|
|||
[message]?(turn: Turn, message: Assertion): void;
|
||||
}
|
||||
|
||||
export class Ref<T> {
|
||||
export class Ref {
|
||||
readonly actor: Actor;
|
||||
readonly target: T;
|
||||
readonly target: Entity;
|
||||
|
||||
constructor(actor: Actor, target: T) {
|
||||
constructor(actor: Actor, target: Entity) {
|
||||
this.actor = actor;
|
||||
this.target = target;
|
||||
}
|
||||
|
||||
sync(turn: Turn, syncable: Ref<LocalAction>) {
|
||||
turn.enqueue(syncable.actor, t => syncable.target(t));
|
||||
sync(turn: Turn, syncable: Ref) {
|
||||
turn.enqueue(syncable.actor, t => t.message(syncable, true));
|
||||
}
|
||||
}
|
||||
|
||||
export type OutboundMap = Map<Handle, Ref<Entity>>;
|
||||
export type OutboundMap = Map<Handle, Ref>;
|
||||
|
||||
export class Actor {
|
||||
readonly outbound: OutboundMap;
|
||||
|
@ -79,7 +79,7 @@ export class Turn {
|
|||
this.actor = actor;
|
||||
}
|
||||
|
||||
ref<T>(t: T): Ref<T> {
|
||||
ref(t: Entity): Ref {
|
||||
return new Ref(this.actor, t);
|
||||
}
|
||||
|
||||
|
@ -99,7 +99,7 @@ export class Turn {
|
|||
this.tasks.push(t => this.actor.terminateWith(t, { ok: true }));
|
||||
}
|
||||
|
||||
assert(location: Ref<Entity>, assertion: Assertion): Handle {
|
||||
assert(location: Ref, assertion: Assertion): Handle {
|
||||
const h = nextHandle++;
|
||||
this.enqueue(location.actor, t => {
|
||||
this.actor.outbound.set(h, location);
|
||||
|
@ -112,24 +112,25 @@ export class Turn {
|
|||
this._retract(this.actor.outbound.get(h)!, h);
|
||||
}
|
||||
|
||||
replace(location: Ref<Entity>, h: Handle | undefined, assertion: Assertion): Handle {
|
||||
replace(location: Ref, h: Handle | undefined, assertion: Assertion): Handle {
|
||||
const newHandle = this.assert(location, assertion);
|
||||
if (h !== void 0) this.retract(h);
|
||||
return newHandle;
|
||||
}
|
||||
|
||||
_retract(location: Ref<Entity>, handle: Handle): void {
|
||||
_retract(location: Ref, handle: Handle): void {
|
||||
this.enqueue(location.actor, t => {
|
||||
this.actor.outbound.delete(handle);
|
||||
location.target[retract]?.(t, handle);
|
||||
});
|
||||
}
|
||||
|
||||
sync(loc: Ref<any>): Promise<Turn> {
|
||||
return new Promise(resolve => this.enqueue(loc.actor, t => loc.sync(t, this.ref(resolve))));
|
||||
sync(loc: Ref): Promise<Turn> {
|
||||
return new Promise(resolve => this.enqueue(loc.actor, t =>
|
||||
loc.sync(t, this.ref({ [message]: resolve }))));
|
||||
}
|
||||
|
||||
message(location: Ref<Entity>, assertion: Assertion): void {
|
||||
message(location: Ref, assertion: Assertion): void {
|
||||
this.enqueue(location.actor, t => location.target[message]?.(t, assertion));
|
||||
}
|
||||
|
||||
|
|
22
main.ts
22
main.ts
|
@ -2,25 +2,25 @@ import { Actor, Assertion, Entity, Handle, Ref, Turn, assert, message, retract }
|
|||
import { Dictionary, IdentityMap, is, Record } from 'preserves';
|
||||
import { Bag, ChangeDescription } from './bag';
|
||||
|
||||
const Observe = Record.makeConstructor<Ref<Entity>>('Observe', ['label', 'observer']);
|
||||
const Observe = Record.makeConstructor<Ref>('Observe', ['label', 'observer']);
|
||||
|
||||
class Dataspace implements Entity {
|
||||
readonly handleMap: IdentityMap<Handle, Record<Ref<Entity>>> = new IdentityMap();
|
||||
readonly assertions = new Bag<Ref<Entity>>();
|
||||
readonly subscriptions: Dictionary<Map<Ref<Entity>, Dictionary<Handle>>> = new Dictionary();
|
||||
readonly handleMap: IdentityMap<Handle, Record<Ref>> = new IdentityMap();
|
||||
readonly assertions = new Bag<Ref>();
|
||||
readonly subscriptions: Dictionary<Map<Ref, Dictionary<Handle>>> = new Dictionary();
|
||||
|
||||
[assert](turn: Turn, rec: Assertion, handle: Handle): void {
|
||||
if (!Record.isRecord<Ref<Entity>>(rec)) return;
|
||||
if (!Record.isRecord<Ref>(rec)) return;
|
||||
this.handleMap.set(handle, rec);
|
||||
if (this.assertions.change(rec, +1) !== ChangeDescription.ABSENT_TO_PRESENT) return;
|
||||
if (Observe.isClassOf(rec)) {
|
||||
const label = Observe._.label(rec)!;
|
||||
const observer = Observe._.observer(rec) as Ref<Entity>;
|
||||
const observer = Observe._.observer(rec) as Ref;
|
||||
const seen = new Dictionary<Handle>();
|
||||
if (!this.subscriptions.has(label)) this.subscriptions.set(label, new Map());
|
||||
this.subscriptions.get(label)!.set(observer, seen);
|
||||
this.assertions.forEach((_count, prev) =>
|
||||
is((prev as Record<Ref<Entity>>).label, label)
|
||||
is((prev as Record<Ref>).label, label)
|
||||
&& seen.set(prev, turn.assert(observer, prev)));
|
||||
}
|
||||
this.subscriptions.get(rec.label)?.forEach((seen, peer) =>
|
||||
|
@ -41,19 +41,19 @@ class Dataspace implements Entity {
|
|||
});
|
||||
if (Observe.isClassOf(rec)) {
|
||||
let peerMap = this.subscriptions.get(Observe._.label(rec)!)!;
|
||||
peerMap.delete(Observe._.observer(rec) as Ref<Entity>);
|
||||
peerMap.delete(Observe._.observer(rec) as Ref);
|
||||
if (peerMap.size === 0) this.subscriptions.delete(Observe._.label(rec)!);
|
||||
}
|
||||
}
|
||||
|
||||
[message](turn: Turn, rec: Assertion): void {
|
||||
if (!Record.isRecord<Ref<Entity>>(rec)) return;
|
||||
if (!Record.isRecord<Ref>(rec)) return;
|
||||
this.subscriptions.get(rec.label)?.forEach((_seen, peer) => turn.message(peer, rec));
|
||||
}
|
||||
}
|
||||
|
||||
const BoxState = Record.makeConstructor<Ref<Entity>>('BoxState', ['value']);
|
||||
const SetBox = Record.makeConstructor<Ref<Entity>>('SetBox', ['newValue']);
|
||||
const BoxState = Record.makeConstructor<Ref>('BoxState', ['value']);
|
||||
const SetBox = Record.makeConstructor<Ref>('SetBox', ['newValue']);
|
||||
|
||||
let startTime = Date.now();
|
||||
let prevValue = 0;
|
||||
|
|
Loading…
Reference in New Issue