diff --git a/main.ts b/main.ts index c77ca8b..66d75fc 100644 --- a/main.ts +++ b/main.ts @@ -15,71 +15,55 @@ import { Bag, ChangeDescription } from './bag'; const Observe = Record.makeConstructor>('Observe', ['label', 'observer']); function makeDataspace(): Entity { - const handleMap: IdentityMap = new IdentityMap(); + const handleMap: IdentityMap>> = new IdentityMap(); const assertions = new Bag>(); const subscriptions: Dictionary, Dictionary>> = new Dictionary(); - function forEachSubscription(assertion: Assertion, f: (handleMap: Dictionary, peer: Ref) => void): void { - if (!Record.isRecord(assertion)) return; + function forEachSubscription(assertion: Record>, f: (seen: Dictionary, peer: Ref) => void): void { subscriptions.get(assertion.label)?.forEach(f); } return { - [assert](turn: Turn, assertion: Assertion, handle: Handle): void { - // console.log(`DS: assert ${assertion.asPreservesText()} :: ${handle}`); - handleMap.set(handle, assertion); - if (assertions.change(assertion, +1) === ChangeDescription.ABSENT_TO_PRESENT) { - if (Observe.isClassOf(assertion)) { - const observedLabel = Observe._.label(assertion)!; - const observer = Observe._.observer(assertion) as Ref; - let peerMap = subscriptions.get(observedLabel); - if (peerMap === void 0) { - peerMap = new Map(); - subscriptions.set(observedLabel, peerMap); - } - const handleMap: Dictionary = new Dictionary(); - peerMap.set(observer, handleMap); - assertions.forEach((_count, assertion) => { - if (Record.isRecord(assertion)) { - if (is(assertion.label, observedLabel)) { - handleMap.set(assertion, turn.assert(observer, assertion)); - } - } - }); - } - forEachSubscription(assertion, (handleMap, peer) => { - if (!handleMap.has(assertion)) { - handleMap.set(assertion, turn.assert(peer, assertion)); - } - }); + [assert](turn: Turn, rec: Assertion, handle: Handle): void { + if (!Record.isRecord>(rec)) return; + handleMap.set(handle, rec); + if (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; + const seen = new Dictionary(); + if (!subscriptions.has(label)) subscriptions.set(label, new Map()); + subscriptions.get(label)!.set(observer, seen); + assertions.forEach((_count, prev) => + is((prev as Record>).label, label) + && seen.set(prev, turn.assert(observer, prev))); } + forEachSubscription(rec, (seen, peer) => + seen.has(rec) || seen.set(rec, turn.assert(peer, rec))); }, [retract](turn: Turn, upstreamHandle: Handle): void { - const assertion = handleMap.get(upstreamHandle); - // console.log(`DS: retract ${(assertion ?? Symbol.for('missing')).asPreservesText()} :: ${upstreamHandle}`); - if (assertion !== void 0) { - handleMap.delete(upstreamHandle); - if (assertions.change(assertion, -1) === ChangeDescription.PRESENT_TO_ABSENT) { - forEachSubscription(assertion, (handleMap, _peer) => { - const downstreamHandle = handleMap.get(assertion); - if (downstreamHandle !== void 0) { - turn.retract(downstreamHandle); - handleMap.delete(assertion); - } - }); - if (Observe.isClassOf(assertion)) { - let peerMap = subscriptions.get(Observe._.label(assertion)!)!; - peerMap.delete(Observe._.observer(assertion)! as Ref); - if (peerMap.size === 0) subscriptions.delete(Observe._.label(assertion)!); - } + const rec = handleMap.get(upstreamHandle); + if (rec === void 0) return; + handleMap.delete(upstreamHandle); + if (assertions.change(rec, -1) !== ChangeDescription.PRESENT_TO_ABSENT) return; + forEachSubscription(rec, (seen, _peer) => { + const downstreamHandle = seen.get(rec); + if (downstreamHandle !== void 0) { + turn.retract(downstreamHandle); + seen.delete(rec); } + }); + if (Observe.isClassOf(rec)) { + let peerMap = subscriptions.get(Observe._.label(rec)!)!; + peerMap.delete(Observe._.observer(rec) as Ref); + if (peerMap.size === 0) subscriptions.delete(Observe._.label(rec)!); } }, - [message](turn: Turn, message: Assertion): void { - // console.log(`DS: message ${message.asPreservesText()}`); - forEachSubscription(message, (_handleMap, peer) => turn.message(peer, message)); + [message](turn: Turn, rec: Assertion): void { + if (!Record.isRecord>(rec)) return; + forEachSubscription(rec, (_seen, peer) => turn.message(peer, rec)); } }; }