Only fire asserted/retracted when first/last interest (dis)/appears; same intent as yesterday's commit b1f7816
This commit is contained in:
parent
f83f4c6413
commit
9312a28226
|
@ -0,0 +1,86 @@
|
||||||
|
// Illustrates the response of asserted / retracted / during to
|
||||||
|
// observation of assertions discarding some of their dimensions.
|
||||||
|
//
|
||||||
|
// Should eventually be turned into some kind of test case.
|
||||||
|
|
||||||
|
var Syndicate = require('./src/main.js');
|
||||||
|
|
||||||
|
var Dataspace = Syndicate.Dataspace;
|
||||||
|
var Patch = Syndicate.Patch;
|
||||||
|
|
||||||
|
var __ = Syndicate.__;
|
||||||
|
|
||||||
|
assertion type ready(what);
|
||||||
|
assertion type entry(key, val);
|
||||||
|
|
||||||
|
ground dataspace {
|
||||||
|
actor {
|
||||||
|
react {
|
||||||
|
assert ready("listener");
|
||||||
|
on asserted entry($key, _) {
|
||||||
|
console.log('key asserted', key);
|
||||||
|
react {
|
||||||
|
on asserted entry(key, $value) { console.log('binding', key, '--->', value); }
|
||||||
|
on retracted entry(key, $value) { console.log('binding', key, '-/->', value); }
|
||||||
|
} until {
|
||||||
|
case retracted entry(key, _) {
|
||||||
|
console.log('key retracted', key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
actor {
|
||||||
|
react {
|
||||||
|
assert ready('other-listener');
|
||||||
|
during entry($key, _) {
|
||||||
|
do { console.log('(other-listener) key asserted', key); }
|
||||||
|
during entry(key, $value) {
|
||||||
|
do { console.log('(other-listener) binding', key, '--->', value); }
|
||||||
|
finally { console.log('(other-listener) binding', key, '-/->', value); }
|
||||||
|
}
|
||||||
|
finally { console.log('(other-listener) key retracted', key); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function pause(k) {
|
||||||
|
console.log('pause');
|
||||||
|
react {
|
||||||
|
assert ready('pause');
|
||||||
|
} until {
|
||||||
|
case asserted ready("pause") {
|
||||||
|
return k();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
actor {
|
||||||
|
react until {
|
||||||
|
case asserted ready("listener") {
|
||||||
|
react until {
|
||||||
|
case asserted ready('other-listener') {
|
||||||
|
Dataspace.stateChange(Patch.assert(entry('a', 1)));
|
||||||
|
Dataspace.stateChange(Patch.assert(entry('a', 2)));
|
||||||
|
Dataspace.stateChange(Patch.assert(entry('b', 3)));
|
||||||
|
Dataspace.stateChange(Patch.assert(entry('c', 33)));
|
||||||
|
Dataspace.stateChange(Patch.assert(entry('a', 4)));
|
||||||
|
Dataspace.stateChange(Patch.assert(entry('a', 5)));
|
||||||
|
pause(function () {
|
||||||
|
Dataspace.stateChange(Patch.retract(entry('a', 2)));
|
||||||
|
Dataspace.stateChange(Patch.retract(entry('c', 33)));
|
||||||
|
Dataspace.stateChange(Patch.assert(entry('a', 9)));
|
||||||
|
pause(function () {
|
||||||
|
Dataspace.stateChange(Patch.retract(entry('a', __)));
|
||||||
|
pause(function () {
|
||||||
|
console.log('done');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -18,6 +18,7 @@ function Actor(state, bootFn) {
|
||||||
this.state = state;
|
this.state = state;
|
||||||
this.facets = Immutable.Set();
|
this.facets = Immutable.Set();
|
||||||
this.mux = new Mux.Mux();
|
this.mux = new Mux.Mux();
|
||||||
|
this.previousKnowledge = Trie.emptyTrie;
|
||||||
this.knowledge = Trie.emptyTrie;
|
this.knowledge = Trie.emptyTrie;
|
||||||
this.pendingActions = [];
|
this.pendingActions = [];
|
||||||
|
|
||||||
|
@ -32,6 +33,7 @@ function Actor(state, bootFn) {
|
||||||
|
|
||||||
Actor.prototype.handleEvent = function(e) {
|
Actor.prototype.handleEvent = function(e) {
|
||||||
if (e.type === 'stateChange') {
|
if (e.type === 'stateChange') {
|
||||||
|
this.previousKnowledge = this.knowledge;
|
||||||
this.knowledge = e.patch.updateInterests(this.knowledge);
|
this.knowledge = e.patch.updateInterests(this.knowledge);
|
||||||
}
|
}
|
||||||
if (this.pendingActions.length > 0) {
|
if (this.pendingActions.length > 0) {
|
||||||
|
@ -81,6 +83,7 @@ function Facet(actor) {
|
||||||
this.doneBlocks = Immutable.List();
|
this.doneBlocks = Immutable.List();
|
||||||
this.children = Immutable.Set();
|
this.children = Immutable.Set();
|
||||||
this.parent = Facet.current;
|
this.parent = Facet.current;
|
||||||
|
this.terminated = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Facet.current = null;
|
Facet.current = null;
|
||||||
|
@ -146,10 +149,18 @@ Facet.prototype.onEvent = function(isTerminal, eventType, subscriptionFn, projec
|
||||||
: e.patch.removed,
|
: e.patch.removed,
|
||||||
spec);
|
spec);
|
||||||
if (objects && objects.size > 0) {
|
if (objects && objects.size > 0) {
|
||||||
// console.log(objects.toArray());
|
|
||||||
if (isTerminal) { facet.terminate(); }
|
|
||||||
facet.actor.pushAction(function () {
|
facet.actor.pushAction(function () {
|
||||||
objects.forEach(function (o) { Util.kwApply(handlerFn, facet.actor.state, o); });
|
var shouldTerminate = isTerminal;
|
||||||
|
objects.forEach(function (o) {
|
||||||
|
var instantiated = Trie.instantiateProjection(spec, o);
|
||||||
|
if (facet.interestWas(eventType, instantiated)) {
|
||||||
|
if (shouldTerminate) {
|
||||||
|
shouldTerminate = false;
|
||||||
|
facet.terminate();
|
||||||
|
}
|
||||||
|
Util.kwApply(handlerFn, facet.actor.state, o);
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -175,6 +186,20 @@ Facet.prototype.onEvent = function(isTerminal, eventType, subscriptionFn, projec
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Facet.prototype.interestWas = function(assertedOrRetracted, pat) {
|
||||||
|
function orStar(a, b) { return (a || b); }
|
||||||
|
var oldExists = Trie.matchValue(this.actor.previousKnowledge, pat, false, orStar);
|
||||||
|
var newExists = Trie.matchValue(this.actor.knowledge, pat, false, orStar);
|
||||||
|
switch (assertedOrRetracted) {
|
||||||
|
case 'asserted':
|
||||||
|
return !oldExists && newExists;
|
||||||
|
case 'retracted':
|
||||||
|
return oldExists && !newExists;
|
||||||
|
default:
|
||||||
|
throw new Error("Unexpected assertedOrRetracted in Facet.interestWas: " + assertedOrRetracted);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
Facet.prototype.addEndpoint = function(endpoint) {
|
Facet.prototype.addEndpoint = function(endpoint) {
|
||||||
var patch = endpoint.subscriptionFn.call(this.actor.state);
|
var patch = endpoint.subscriptionFn.call(this.actor.state);
|
||||||
var r = this.actor.mux.addStream(patch);
|
var r = this.actor.mux.addStream(patch);
|
||||||
|
@ -220,20 +245,28 @@ Facet.prototype.completeBuild = function() {
|
||||||
|
|
||||||
Facet.prototype.terminate = function() {
|
Facet.prototype.terminate = function() {
|
||||||
var facet = this;
|
var facet = this;
|
||||||
|
|
||||||
|
if (facet.terminated) return;
|
||||||
|
facet.terminated = true;
|
||||||
|
|
||||||
var aggregate = Patch.emptyPatch;
|
var aggregate = Patch.emptyPatch;
|
||||||
this.endpoints.forEach(function(endpoint, eid) {
|
this.endpoints.forEach(function(endpoint, eid) {
|
||||||
var r = facet.actor.mux.removeStream(eid);
|
var r = facet.actor.mux.removeStream(eid);
|
||||||
aggregate = aggregate.andThen(r.deltaAggregate);
|
aggregate = aggregate.andThen(r.deltaAggregate);
|
||||||
});
|
});
|
||||||
Dataspace.stateChange(aggregate);
|
Dataspace.stateChange(aggregate);
|
||||||
|
|
||||||
this.endpoints = Immutable.Map();
|
this.endpoints = Immutable.Map();
|
||||||
if (this.parent) {
|
if (this.parent) {
|
||||||
this.parent.children = this.parent.children.remove(this);
|
this.parent.children = this.parent.children.remove(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.actor.removeFacet(this);
|
this.actor.removeFacet(this);
|
||||||
|
|
||||||
withCurrentFacet(facet, function () {
|
withCurrentFacet(facet, function () {
|
||||||
facet.doneBlocks.forEach(function(b) { b.call(facet.actor.state); });
|
facet.doneBlocks.forEach(function(b) { b.call(facet.actor.state); });
|
||||||
});
|
});
|
||||||
|
|
||||||
this.children.forEach(function (child) {
|
this.children.forEach(function (child) {
|
||||||
child.terminate();
|
child.terminate();
|
||||||
});
|
});
|
||||||
|
|
|
@ -765,6 +765,38 @@ function projectObjects(m, projection) {
|
||||||
return trieKeysToObjects(trieKeys(project(m, projection), names.length), names);
|
return trieKeysToObjects(trieKeys(project(m, projection), names.length), names);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// (Projection, CaptureObject) -> Pattern
|
||||||
|
function instantiateProjection(p, obj) {
|
||||||
|
var captureCount = 0;
|
||||||
|
return walk(p);
|
||||||
|
|
||||||
|
function walk(p) {
|
||||||
|
if (isCapture(p)) {
|
||||||
|
var thisCapture = captureCount++;
|
||||||
|
var name = captureName(p);
|
||||||
|
return (name !== null) ? obj[name] : obj['$' + thisCapture];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Array.isArray(p)) {
|
||||||
|
var result = [];
|
||||||
|
for (var i = 0; i < p.length; i++) {
|
||||||
|
result.push(walk(p[i]));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Struct.isStructure(p)) {
|
||||||
|
var resultFields = [];
|
||||||
|
for (var i = 0; i < p.meta.arity; i++) {
|
||||||
|
resultFields[i] = walk(p[i]);
|
||||||
|
}
|
||||||
|
return new Struct.Structure(p.meta, resultFields);
|
||||||
|
}
|
||||||
|
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function prettyTrie(m, initialIndent) {
|
function prettyTrie(m, initialIndent) {
|
||||||
var acc = [];
|
var acc = [];
|
||||||
walk(initialIndent || 0, m);
|
walk(initialIndent || 0, m);
|
||||||
|
@ -928,6 +960,7 @@ module.exports.trieKeys = trieKeys;
|
||||||
module.exports.captureToObject = captureToObject;
|
module.exports.captureToObject = captureToObject;
|
||||||
module.exports.trieKeysToObjects = trieKeysToObjects;
|
module.exports.trieKeysToObjects = trieKeysToObjects;
|
||||||
module.exports.projectObjects = projectObjects;
|
module.exports.projectObjects = projectObjects;
|
||||||
|
module.exports.instantiateProjection = instantiateProjection;
|
||||||
module.exports.prettyTrie = prettyTrie;
|
module.exports.prettyTrie = prettyTrie;
|
||||||
module.exports.trieToJSON = trieToJSON;
|
module.exports.trieToJSON = trieToJSON;
|
||||||
module.exports.trieFromJSON = trieFromJSON;
|
module.exports.trieFromJSON = trieFromJSON;
|
||||||
|
|
Loading…
Reference in New Issue