state-trooper
Version:
Application State Manager
112 lines (95 loc) • 2.56 kB
JavaScript
;
var Box = require("./channels").Box;
var AltHandler = function(flag, f) {
this.f = f;
this.flag = flag;
};
AltHandler.prototype.is_active = function() {
return this.flag.value;
};
AltHandler.prototype.is_blockable = function() {
return true;
};
AltHandler.prototype.commit = function() {
this.flag.value = false;
return this.f;
};
var AltResult = function(value, channel) {
this.value = value;
this.channel = channel;
};
function rand_int(n) {
return Math.floor(Math.random() * (n + 1));
}
function random_array(n) {
var a = new Array(n);
var i;
for (i = 0; i < n; i++) {
a[i] = 0;
}
for (i = 1; i < n; i++) {
var j = rand_int(i);
a[i] = a[j];
a[j] = i;
}
return a;
}
var hasOwnProperty = Object.prototype.hasOwnProperty;
var DEFAULT = {
toString: function() {
return "[object DEFAULT]";
}
};
// TODO: Accept a priority function or something
exports.do_alts = function(operations, callback, options) {
var length = operations.length;
// XXX Hmm
if (length === 0) {
throw new Error("Empty alt list");
}
var priority = (options && options.priority) ? true : false;
if (!priority) {
var indexes = random_array(length);
}
var flag = new Box(true);
for (var i = 0; i < length; i++) {
var operation = operations[priority ? i : indexes[i]];
var port, result;
// XXX Hmm
if (operation instanceof Array) {
var value = operation[1];
port = operation[0];
// We wrap this in a function to capture the value of "port",
// because js' closure captures vars by "references", not
// values. "let port" would have worked, but I don't want to
// raise the runtime requirement yet. TODO: So change this when
// most runtimes are modern enough.
result = port._put(value, (function(port) {
return new AltHandler(flag, function(ok) {
callback(new AltResult(ok, port));
});
})(port));
} else {
port = operation;
result = port._take((function(port) {
return new AltHandler(flag, function(value) {
callback(new AltResult(value, port));
});
})(port));
}
// XXX Hmm
if (result instanceof Box) {
callback(new AltResult(result.value, port));
break;
}
}
if (!(result instanceof Box)
&& options
&& hasOwnProperty.call(options, "default")) {
if (flag.value) {
flag.value = false;
callback(new AltResult(options["default"], DEFAULT));
}
}
};
exports.DEFAULT = DEFAULT;